Roll Observatory deps (charted -> ^0.3.0)

I had to restrict both the analyzer and dart_style to old versions to
get the build to work :-/.  Otherwise I got errors like this:

    Transform polymer (PolymerBootstrapTransformer) on
    observatory|web/index.html threw error: Class 'Parser' has no
    instance setter 'parseConditionalDirectives='.

Added missing exclude to pubspec.yaml.

BUG=

Review URL: https://codereview.chromium.org//1521693002 .
diff --git a/packages/analyzer/CHANGELOG.md b/packages/analyzer/CHANGELOG.md
index 9e2232a..aa44b2c 100644
--- a/packages/analyzer/CHANGELOG.md
+++ b/packages/analyzer/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 0.26.1+13
+* (Internal) Plugin processing fixes.
+
+## 0.26.1+11
+* Fixes to address lint registry memory leaking.
+
+## 0.26.1+10
+* New `AnalysisContext` API for associating configuration data with contexts
+  (`setConfigurationData()` and `getConfigurationData()`).
+
 ## 0.26.1+9
 * `OptionsProcessor` extension point API changed to pass associated
   `AnalysisContext` instance into the `optionsProcessed` call-back.
diff --git a/packages/analyzer/lib/file_system/memory_file_system.dart b/packages/analyzer/lib/file_system/memory_file_system.dart
index 1684fe9..058f9eb 100644
--- a/packages/analyzer/lib/file_system/memory_file_system.dart
+++ b/packages/analyzer/lib/file_system/memory_file_system.dart
@@ -363,7 +363,13 @@
 
   @override
   Uri resolveRelativeUri(Uri relativeUri) {
-    return uri.resolveUri(relativeUri);
+    Uri baseUri = uri;
+    String scheme = uri.scheme;
+    if (scheme == DartUriResolver.DART_SCHEME) {
+      String libraryName = uri.path;
+      baseUri = Uri.parse('$scheme:$libraryName/$libraryName.dart');
+    }
+    return baseUri.resolveUri(relativeUri);
   }
 
   @override
diff --git a/packages/analyzer/lib/source/analysis_options_provider.dart b/packages/analyzer/lib/source/analysis_options_provider.dart
index 1c05375..aeac053 100644
--- a/packages/analyzer/lib/source/analysis_options_provider.dart
+++ b/packages/analyzer/lib/source/analysis_options_provider.dart
@@ -5,18 +5,16 @@
 library source.analysis_options_provider;
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:yaml/yaml.dart';
 
 /// Provide the options found in the `.analysis_options` file.
 class AnalysisOptionsProvider {
-  /// The name of the analysis options source file.
-  static const String ANALYSIS_OPTIONS_NAME = '.analysis_options';
-
-  /// Provide the options found in [root]/[ANALYSIS_OPTIONS_NAME].
+  /// Provide the options found in [root]/[ANALYSIS_OPTIONS_FILE].
   /// Return an empty options map if the file does not exist.
   Map<String, YamlNode> getOptions(Folder root) {
-    var optionsSource =
-        _readAnalysisOptionsFile(root.getChild(ANALYSIS_OPTIONS_NAME));
+    var optionsSource = _readAnalysisOptionsFile(
+        root.getChild(AnalysisEngine.ANALYSIS_OPTIONS_FILE));
     return getOptionsFromString(optionsSource);
   }
 
diff --git a/packages/analyzer/lib/src/context/context.dart b/packages/analyzer/lib/src/context/context.dart
index 893ae9f..dd2893f 100644
--- a/packages/analyzer/lib/src/context/context.dart
+++ b/packages/analyzer/lib/src/context/context.dart
@@ -115,6 +115,12 @@
   AnalysisCache _cache;
 
   /**
+   * Configuration data associated with this context.
+   */
+  final HashMap<ResultDescriptor, Object> _configurationData =
+      new HashMap<ResultDescriptor, Object>();
+
+  /**
    * The task manager used to manage the tasks used to analyze code.
    */
   TaskManager _taskManager;
@@ -409,6 +415,13 @@
     }
   }
 
+  /**
+   * Invalidate analysis cache.
+   */
+  void invalidateCachedResults() {
+    _cache = createCacheFromSourceFactory(_sourceFactory);
+  }
+
   @override
   List<Source> get sources {
     return _cache.sources.toList();
@@ -583,12 +596,10 @@
   @override
   List<AnalysisError> computeErrors(Source source) {
     String name = source.shortName;
-    if (AnalysisEngine.isDartFileName(name)) {
-      return computeResult(source, DART_ERRORS);
-    } else if (AnalysisEngine.isHtmlFileName(name)) {
+    if (AnalysisEngine.isHtmlFileName(name)) {
       return computeResult(source, HTML_ERRORS);
     }
-    return AnalysisError.NO_ERRORS;
+    return computeResult(source, DART_ERRORS);
   }
 
   @override
@@ -766,6 +777,9 @@
   }
 
   @override
+  Object getConfigurationData(ResultDescriptor key) => _configurationData[key];
+
+  @override
   TimestampedData<String> getContents(Source source) {
     String contents = _contentCache.getContents(source);
     if (contents != null) {
@@ -1152,8 +1166,10 @@
       entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
       entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
       entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
+      entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
       // USED_IMPORTED_ELEMENTS
       // USED_LOCAL_ELEMENTS
+      setValue(STRONG_MODE_ERRORS, AnalysisError.NO_ERRORS);
       setValue(VARIABLE_REFERENCE_ERRORS, AnalysisError.NO_ERRORS);
       setValue(VERIFY_ERRORS, AnalysisError.NO_ERRORS);
     });
@@ -1201,6 +1217,11 @@
   }
 
   @override
+  void setConfigurationData(ResultDescriptor key, Object data) {
+    _configurationData[key] = data;
+  }
+
+  @override
   void setContents(Source source, String contents) {
     _contentsChanged(source, contents, true);
   }
@@ -1230,6 +1251,7 @@
     entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
     entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
   }
 
diff --git a/packages/analyzer/lib/src/generated/ast.dart b/packages/analyzer/lib/src/generated/ast.dart
index 4b83206..03cb8f1 100644
--- a/packages/analyzer/lib/src/generated/ast.dart
+++ b/packages/analyzer/lib/src/generated/ast.dart
@@ -423,10 +423,8 @@
   @override
   Token get beginToken => leftParenthesis;
 
-  /**
-   * TODO(paulberry): Add commas.
-   */
   @override
+  // TODO(paulberry): Add commas.
   Iterable get childEntities => new ChildEntities()
     ..add(leftParenthesis)
     ..addAll(_arguments)
@@ -3836,7 +3834,7 @@
   Token get keyword => breakKeyword;
 
   /**
-   * Sethe token representing the 'break' keyword to the given [token].
+   * Set the token representing the 'break' keyword to the given [token].
    */
   @deprecated // Use "this.breakKeyword"
   void set keyword(Token token) {
@@ -9478,10 +9476,8 @@
   @override
   Token get beginToken => implementsKeyword;
 
-  /**
-   * TODO(paulberry): add commas.
-   */
   @override
+  // TODO(paulberry): add commas.
   Iterable get childEntities => new ChildEntities()
     ..add(implementsKeyword)
     ..addAll(interfaces);
@@ -11657,10 +11653,8 @@
   @override
   Element get bestElement => staticElement;
 
-  /**
-   * TODO(paulberry): add "." tokens.
-   */
   @override
+  // TODO(paulberry): add "." tokens.
   Iterable get childEntities => new ChildEntities()..addAll(_components);
 
   /**
@@ -11750,10 +11744,8 @@
     return leftBracket;
   }
 
-  /**
-   * TODO(paulberry): add commas.
-   */
   @override
+  // TODO(paulberry): add commas.
   Iterable get childEntities => super._childEntities
     ..add(leftBracket)
     ..addAll(_elements)
@@ -11840,10 +11832,8 @@
     return leftBracket;
   }
 
-  /**
-   * TODO(paulberry): add commas.
-   */
   @override
+  // TODO(paulberry): add commas.
   Iterable get childEntities => super._childEntities
     ..add(leftBracket)
     ..addAll(entries)
@@ -12611,7 +12601,7 @@
   StringLiteral get name => _name;
 
   /**
-   * Sets the name of the native object that implements the class to the given
+   * Set the name of the native object that implements the class to the given
    * [name].
    */
   void set name(StringLiteral name) {
@@ -16198,10 +16188,8 @@
     _shownNames = new NodeList<SimpleIdentifier>(this, shownNames);
   }
 
-  /**
-   * TODO(paulberry): add commas.
-   */
   @override
+  // TODO(paulberry): add commas.
   Iterable get childEntities => new ChildEntities()
     ..add(keyword)
     ..addAll(_shownNames);
@@ -16700,7 +16688,7 @@
   Token get endToken => token;
 
   /**
-   * Returns `true` if this identifier is the "name" part of a prefixed
+   * Return `true` if this identifier is the "name" part of a prefixed
    * identifier or a method invocation.
    */
   bool get isQualified {
@@ -17785,10 +17773,8 @@
   @override
   Token get beginToken => poundSign;
 
-  /**
-   * TODO(paulberry): add "." tokens.
-   */
   @override
+  // TODO(paulberry): add "." tokens.
   Iterable get childEntities => new ChildEntities()
     ..add(poundSign)
     ..addAll(components);
@@ -18359,6 +18345,7 @@
 
   @override
   Object visitFieldFormalParameter(FieldFormalParameter node) {
+    _visitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
     _visitTokenWithSuffix(node.keyword, " ");
     _visitNodeWithSuffix(node.type, " ");
     _writer.print("this.");
@@ -18484,6 +18471,7 @@
 
   @override
   Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+    _visitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
     _visitNodeWithSuffix(node.returnType, " ");
     _visitNode(node.identifier);
     _visitNode(node.typeParameters);
@@ -18814,6 +18802,7 @@
 
   @override
   Object visitSimpleFormalParameter(SimpleFormalParameter node) {
+    _visitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
     _visitTokenWithSuffix(node.keyword, " ");
     _visitNodeWithSuffix(node.type, " ");
     _visitNode(node.identifier);
@@ -19322,10 +19311,8 @@
   @override
   Token get beginToken => leftBracket;
 
-  /**
-   * TODO(paulberry): Add commas.
-   */
   @override
+  // TODO(paulberry): Add commas.
   Iterable get childEntities => new ChildEntities()
     ..add(leftBracket)
     ..addAll(_arguments)
@@ -20303,10 +20290,8 @@
     _variables = new NodeList<VariableDeclaration>(this, variables);
   }
 
-  /**
-   * TODO(paulberry): include commas.
-   */
   @override
+  // TODO(paulberry): include commas.
   Iterable get childEntities => super._childEntities
     ..add(keyword)
     ..add(_type)
@@ -20559,10 +20544,8 @@
   @override
   Token get beginToken => withKeyword;
 
-  /**
-   * TODO(paulberry): add commas.
-   */
   @override
+  // TODO(paulberry): add commas.
   Iterable get childEntities => new ChildEntities()
     ..add(withKeyword)
     ..addAll(_mixinTypes);
diff --git a/packages/analyzer/lib/src/generated/constant.dart b/packages/analyzer/lib/src/generated/constant.dart
index 0f4c0f6..c2ec01e 100644
--- a/packages/analyzer/lib/src/generated/constant.dart
+++ b/packages/analyzer/lib/src/generated/constant.dart
@@ -311,7 +311,7 @@
     if (!identical(argumentValues[0].type, typeProvider.stringType)) {
       return false;
     }
-    String name = argumentValues[0].stringValue;
+    String name = argumentValues[0].toStringValue();
     return isValidPublicSymbol(name);
   }
 
@@ -626,7 +626,7 @@
           return null;
         }
         String variableName =
-            argumentCount < 1 ? null : argumentValues[0].stringValue;
+            argumentCount < 1 ? null : argumentValues[0].toStringValue();
         if (identical(definingClass, typeProvider.boolType)) {
           DartObject valueFromEnvironment;
           valueFromEnvironment =
@@ -661,7 +661,7 @@
               CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
           return null;
         }
-        String argumentValue = argumentValues[0].stringValue;
+        String argumentValue = argumentValues[0].toStringValue();
         return new DartObjectImpl(
             definingClass, new SymbolState(argumentValue));
       }
@@ -1598,9 +1598,9 @@
     if (conditionResult == null) {
       return conditionResult;
     }
-    if (conditionResult.isTrue) {
+    if (conditionResult.toBoolValue() == true) {
       return thenResult;
-    } else if (conditionResult.isFalse) {
+    } else if (conditionResult.toBoolValue() == false) {
       return elseResult;
     }
     ParameterizedType thenType = thenResult.type;
@@ -1936,64 +1936,214 @@
 }
 
 /**
- * The state of a Dart object.
+ * A representation of the value of a compile-time constant expression.
+ *
+ * Note that, unlike the mirrors system, the object being represented does *not*
+ * exist. This interface allows static analysis tools to determine something
+ * about the state of the object that would exist if the code that creates the
+ * object were executed, but none of the code being analyzed is actually
+ * executed.
  */
 abstract class DartObject {
   /**
    * Return the boolean value of this object, or `null` if either the value of
    * this object is not known or this object is not of type 'bool'.
+   *
+   * Deprecated. Use [toBoolValue].
    */
+  @deprecated
   bool get boolValue;
 
   /**
    * Return the floating point value of this object, or `null` if either the
    * value of this object is not known or this object is not of type 'double'.
+   *
+   * Deprecated. Use [toDoubleValue].
    */
+  @deprecated
   double get doubleValue;
 
   /**
    * Return `true` if this object's value can be represented exactly.
+   *
+   * Deprecated. The semantics of this method were not clear. One semantic is
+   * covered by [hasKnownValue].
    */
+  @deprecated
   bool get hasExactValue;
 
   /**
+   * Return `true` if the value of the object being represented is known.
+   *
+   * This method will return `false` if
+   * * the value being represented is the value of a declared variable (a
+   *   variable whose value is provided at run-time using a `-D` command-line
+   *   option), or
+   * * the value is a function.
+   *
+   * The result of this method does not imply anything about the state of
+   * object representations returned by the method [getField], those that are
+   * elements of the list returned by [toListValue], or the keys or values in
+   * the map returned by [toMapValue]. For example, a representation of a list
+   * can return `true` even if one or more of the elements of that list would
+   * return `false`.
+   */
+  bool get hasKnownValue;
+
+  /**
    * Return the integer value of this object, or `null` if either the value of
    * this object is not known or this object is not of type 'int'.
+   *
+   * Deprecated. Use [toIntValue].
    */
+  @deprecated
   int get intValue;
 
   /**
    * Return `true` if this object represents the value 'false'.
+   *
+   * Deprecated. Use `object.toBoolValue() == false`.
    */
+  @deprecated
   bool get isFalse;
 
   /**
-   * Return `true` if this object represents the value 'null'.
+   * Return `true` if the object being represented represents the value 'null'.
    */
   bool get isNull;
 
   /**
    * Return `true` if this object represents the value 'true'.
+   *
+   * Deprecated. Use `object.toBoolValue() == true`.
    */
+  @deprecated
   bool get isTrue;
 
   /**
    * Return the string value of this object, or `null` if either the value of
    * this object is not known or this object is not of type 'String'.
+   *
+   * Deprecated. Use [toStringValue].
    */
+  @deprecated
   String get stringValue;
 
   /**
-   * Return the run-time type of this object.
+   * Return a representation of the type of the object being represented.
+   *
+   * For values resulting from the invocation of a 'const' constructor, this
+   * will be a representation of the run-time type of the object.
+   *
+   * For values resulting from a literal expression, this will be a
+   * representation of the static type of the value -- `int` for integer
+   * literals, `List` for list literals, etc. -- even when the static type is an
+   * abstract type (such as `List`) and hence will never be the run-time type of
+   * the represented object.
+   *
+   * For values resulting from any other kind of expression, this will be a
+   * representation of the result of evaluating the expression.
+   *
+   * Return `null` if the expression cannot be evaluated, either because it is
+   * not a valid constant expression or because one or more of the values used
+   * in the expression does not have a known value.
+   *
+   * This method can return a representation of the type, even if this object
+   * would return `false` from [hasKnownValue].
    */
   ParameterizedType get type;
 
   /**
    * Return this object's value if it can be represented exactly, or `null` if
    * either the value cannot be represented exactly or if the value is `null`.
-   * Clients should use [hasExactValue] to distinguish between these two cases.
+   * Clients should use `hasExactValue` to distinguish between these two cases.
+   *
+   * Deprecated. Use one of the `isXValue()` methods.
    */
+  @deprecated
   Object get value;
+
+  /**
+   * Return a representation of the value of the field with the given [name].
+   *
+   * Return `null` if either the object being represented does not have a field
+   * with the given name or if the implementation of the class of the object is
+   * invalid, making it impossible to determine that value of the field.
+   *
+   * Note that, unlike the mirrors API, this method does *not* invoke a getter;
+   * it simply returns a representation of the known state of a field.
+   */
+  DartObject getField(String name);
+
+  /**
+   * Return a boolean corresponding to the value of the object being
+   * represented, or `null` if
+   * * this object is not of type 'bool',
+   * * the value of the object being represented is not known, or
+   * * the value of the object being represented is `null`.
+   */
+  bool toBoolValue();
+
+  /**
+   * Return a double corresponding to the value of the object being represented,
+   * or `null`
+   * if
+   * * this object is not of type 'double',
+   * * the value of the object being represented is not known, or
+   * * the value of the object being represented is `null`.
+   */
+  double toDoubleValue();
+
+  /**
+   * Return an integer corresponding to the value of the object being
+   * represented, or `null` if
+   * * this object is not of type 'int',
+   * * the value of the object being represented is not known, or
+   * * the value of the object being represented is `null`.
+   */
+  int toIntValue();
+
+  /**
+   * Return a list corresponding to the value of the object being represented,
+   * or `null` if
+   * * this object is not of type 'List', or
+   * * the value of the object being represented is `null`.
+   */
+  List<DartObject> toListValue();
+
+  /**
+   * Return a map corresponding to the value of the object being represented, or
+   * `null` if
+   * * this object is not of type 'Map', or
+   * * the value of the object being represented is `null`.
+   */
+  Map<DartObject, DartObject> toMapValue();
+
+  /**
+   * Return a string corresponding to the value of the object being represented,
+   * or `null` if
+   * * this object is not of type 'String',
+   * * the value of the object being represented is not known, or
+   * * the value of the object being represented is `null`.
+   */
+  String toStringValue();
+
+  /**
+   * Return a string corresponding to the value of the object being represented,
+   * or `null` if
+   * * this object is not of type 'Symbol', or
+   * * the value of the object being represented is `null`.
+   * (We return the string
+   */
+  String toSymbolValue();
+
+  /**
+   * Return the representation of the type corresponding to the value of the
+   * object being represented, or `null` if
+   * * this object is not of type 'Type', or
+   * * the value of the object being represented is `null`.
+   */
+  ParameterizedType toTypeValue();
 }
 
 /**
@@ -2390,24 +2540,17 @@
     return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
   }
 
+  @deprecated
   @override
-  bool get boolValue {
-    if (_state is BoolState) {
-      return (_state as BoolState).value;
-    }
-    return null;
-  }
+  bool get boolValue => toBoolValue();
 
+  @deprecated
   @override
-  double get doubleValue {
-    if (_state is DoubleState) {
-      return (_state as DoubleState).value;
-    }
-    return null;
-  }
+  double get doubleValue => toDoubleValue();
 
   HashMap<String, DartObjectImpl> get fields => _state.fields;
 
+  @deprecated
   @override
   bool get hasExactValue => _state.hasExactValue;
 
@@ -2415,12 +2558,11 @@
   int get hashCode => JenkinsSmiHash.hash2(type.hashCode, _state.hashCode);
 
   @override
-  int get intValue {
-    if (_state is IntState) {
-      return (_state as IntState).value;
-    }
-    return null;
-  }
+  bool get hasKnownValue => !_state.isUnknown;
+
+  @deprecated
+  @override
+  int get intValue => toIntValue();
 
   /**
    * Return `true` if this object represents an object whose type is 'bool'.
@@ -2433,13 +2575,14 @@
    */
   bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull;
 
+  @deprecated
   @override
-  bool get isFalse =>
-      _state is BoolState && identical((_state as BoolState).value, false);
+  bool get isFalse => toBoolValue() == false;
 
   @override
   bool get isNull => _state is NullState;
 
+  @deprecated
   @override
   bool get isTrue =>
       _state is BoolState && identical((_state as BoolState).value, true);
@@ -2455,14 +2598,11 @@
    */
   bool get isUserDefinedObject => _state is GenericState;
 
+  @deprecated
   @override
-  String get stringValue {
-    if (_state is StringState) {
-      return (_state as StringState).value;
-    }
-    return null;
-  }
+  String get stringValue => toStringValue();
 
+  @deprecated
   @override
   Object get value => _state.value;
 
@@ -2624,6 +2764,14 @@
         typeProvider.boolType, _state.equalEqual(rightOperand._state));
   }
 
+  @override
+  DartObject getField(String name) {
+    if (_state is GenericState) {
+      return (_state as GenericState).fields[name];
+    }
+    return null;
+  }
+
   /**
    * Return the result of invoking the '&gt;' operator on this object with the
    * [rightOperand]. The [typeProvider] is the type provider used to find known
@@ -2897,7 +3045,77 @@
   }
 
   @override
+  bool toBoolValue() {
+    if (_state is BoolState) {
+      return (_state as BoolState).value;
+    }
+    return null;
+  }
+
+  @override
+  double toDoubleValue() {
+    if (_state is DoubleState) {
+      return (_state as DoubleState).value;
+    }
+    return null;
+  }
+
+  @override
+  int toIntValue() {
+    if (_state is IntState) {
+      return (_state as IntState).value;
+    }
+    return null;
+  }
+
+  @override
+  List<DartObject> toListValue() {
+    if (_state is ListState) {
+      return (_state as ListState)._elements;
+    }
+    return null;
+  }
+
+  @override
+  Map<DartObject, DartObject> toMapValue() {
+    if (_state is MapState) {
+      return (_state as MapState)._entries;
+    }
+    return null;
+  }
+
+  @override
   String toString() => "${type.displayName} ($_state)";
+
+  @override
+  String toStringValue() {
+    if (_state is StringState) {
+      return (_state as StringState).value;
+    }
+    return null;
+  }
+
+  @override
+  String toSymbolValue() {
+    if (_state is SymbolState) {
+      return (_state as SymbolState).value;
+    }
+    return null;
+  }
+
+  @override
+  ParameterizedType toTypeValue() {
+    if (_state is TypeState) {
+      Element element = (_state as TypeState).value;
+      if (element is ClassElement) {
+        return element.type;
+      }
+      if (element is FunctionElement) {
+        return element.type;
+      }
+    }
+    return null;
+  }
 }
 
 /**
diff --git a/packages/analyzer/lib/src/generated/element.dart b/packages/analyzer/lib/src/generated/element.dart
index 9e7aeb4..0fcb8e5 100644
--- a/packages/analyzer/lib/src/generated/element.dart
+++ b/packages/analyzer/lib/src/generated/element.dart
@@ -13,7 +13,7 @@
     show AnalysisTarget, ConstantEvaluationTarget;
 
 import 'ast.dart';
-import 'constant.dart' show EvaluationResultImpl;
+import 'constant.dart' show DartObject, EvaluationResultImpl;
 import 'engine.dart' show AnalysisContext, AnalysisEngine, AnalysisException;
 import 'html.dart' show XmlAttributeNode, XmlTagNode;
 import 'java_core.dart';
@@ -1760,6 +1760,9 @@
   ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
 
   @override
+  DartObject get constantValue => _result.value;
+
+  @override
   EvaluationResultImpl get evaluationResult => _result;
 
   @override
@@ -1791,6 +1794,9 @@
   ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
 
   @override
+  DartObject get constantValue => _result.value;
+
+  @override
   EvaluationResultImpl get evaluationResult => _result;
 
   @override
@@ -2109,6 +2115,9 @@
   ConstTopLevelVariableElementImpl(Identifier name) : super.forNode(name);
 
   @override
+  DartObject get constantValue => _result.value;
+
+  @override
   EvaluationResultImpl get evaluationResult => _result;
 
   @override
@@ -2273,6 +2282,9 @@
   DefaultFieldFormalParameterElementImpl(Identifier name) : super(name);
 
   @override
+  DartObject get constantValue => _result.value;
+
+  @override
   EvaluationResultImpl get evaluationResult => _result;
 
   @override
@@ -2297,6 +2309,9 @@
   DefaultParameterElementImpl(Identifier name) : super.forNode(name);
 
   @override
+  DartObject get constantValue => _result.value;
+
+  @override
   EvaluationResultImpl get evaluationResult => _result;
 
   @override
@@ -2659,6 +2674,14 @@
   static const List<ElementAnnotation> EMPTY_LIST = const <ElementAnnotation>[];
 
   /**
+   * Return a representation of the value of this annotation.
+   *
+   * Return `null` if the value of this annotation could not be computed because
+   * of errors.
+   */
+  DartObject get constantValue;
+
+  /**
    * Return the element representing the field, variable, or const constructor
    * being used as an annotation.
    */
@@ -2738,6 +2761,9 @@
   ElementAnnotationImpl(this.element);
 
   @override
+  DartObject get constantValue => evaluationResult.value;
+
+  @override
   bool get isDeprecated {
     if (element != null) {
       LibraryElement library = element.library;
@@ -10610,6 +10636,15 @@
   static const List<VariableElement> EMPTY_LIST = const <VariableElement>[];
 
   /**
+   * Return a representation of the value of this variable.
+   *
+   * Return `null` if either this variable was not declared with the 'const'
+   * modifier or if the value of this variable could not be computed because of
+   * errors.
+   */
+  DartObject get constantValue;
+
+  /**
    * Return `true` if this variable element did not have an explicit type
    * specified for it.
    */
@@ -10712,6 +10747,9 @@
     setModifier(Modifier.CONST, isConst);
   }
 
+  @override
+  DartObject get constantValue => null;
+
   /**
    * Return the result of evaluating this variable's initializer as a
    * compile-time constant expression, or `null` if this variable is not a
@@ -10805,6 +10843,9 @@
   VariableElement get baseElement => super.baseElement as VariableElement;
 
   @override
+  DartObject get constantValue => baseElement.constantValue;
+
+  @override
   bool get hasImplicitType => baseElement.hasImplicitType;
 
   @override
diff --git a/packages/analyzer/lib/src/generated/element_handle.dart b/packages/analyzer/lib/src/generated/element_handle.dart
index 338a279..f496602 100644
--- a/packages/analyzer/lib/src/generated/element_handle.dart
+++ b/packages/analyzer/lib/src/generated/element_handle.dart
@@ -4,14 +4,15 @@
 
 library engine.element_handle;
 
-import 'ast.dart';
-import 'element.dart';
-import 'engine.dart';
-import 'java_core.dart';
-import 'java_engine.dart';
-import 'resolver.dart';
-import 'source.dart';
-import 'utilities_dart.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
 
 /**
  * Instances of the class `ClassElementHandle` implement a handle to a `ClassElement`.
@@ -1092,6 +1093,9 @@
   VariableElement get actualElement => super.actualElement as VariableElement;
 
   @override
+  DartObject get constantValue => actualElement.constantValue;
+
+  @override
   bool get hasImplicitType => actualElement.hasImplicitType;
 
   @override
diff --git a/packages/analyzer/lib/src/generated/element_resolver.dart b/packages/analyzer/lib/src/generated/element_resolver.dart
index ab8fe91..ffe623b 100644
--- a/packages/analyzer/lib/src/generated/element_resolver.dart
+++ b/packages/analyzer/lib/src/generated/element_resolver.dart
@@ -974,10 +974,18 @@
       return null;
     }
     //
-    // We ignore identifiers that have already been resolved, such as
-    // identifiers representing the name in a declaration.
+    // Ignore nodes that should have been resolved before getting here.
     //
-    if (node.staticElement != null) {
+    if (node.inDeclarationContext()) {
+      return null;
+    }
+    AstNode parent = node.parent;
+    if (parent is FieldFormalParameter) {
+      return null;
+    } else if (parent is ConstructorFieldInitializer &&
+        parent.fieldName == node) {
+      return null;
+    } else if (parent is Annotation && parent.constructorName == node) {
       return null;
     }
     //
diff --git a/packages/analyzer/lib/src/generated/engine.dart b/packages/analyzer/lib/src/generated/engine.dart
index 9560bff..acb156e 100644
--- a/packages/analyzer/lib/src/generated/engine.dart
+++ b/packages/analyzer/lib/src/generated/engine.dart
@@ -18,8 +18,10 @@
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/manager.dart';
 import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart' as newContext;
 import 'package:analyzer/task/model.dart';
 import 'package:html/dom.dart' show Document;
+import 'package:path/path.dart' as pathos;
 import 'package:plugin/manager.dart';
 import 'package:plugin/plugin.dart';
 
@@ -589,6 +591,14 @@
       Source unitSource, Source librarySource);
 
   /**
+   * Return configuration data associated with the given key or `null` if no
+   * state has been associated with the given [key].
+   *
+   * See [setConfigurationData].
+   */
+  Object getConfigurationData(ResultDescriptor key);
+
+  /**
    * Return the contents and timestamp of the given [source].
    *
    * This method should be used rather than the method [Source.getContents]
@@ -885,6 +895,13 @@
       Source source, String contents, int offset, int oldLength, int newLength);
 
   /**
+   * Associate this configuration [data] object with the given descriptor [key].
+   *
+   * See [getConfigurationData].
+   */
+  void setConfigurationData(ResultDescriptor key, Object data);
+
+  /**
    * Set the contents of the given [source] to the given [contents] and mark the
    * source as having changed. This has the effect of overriding the default
    * contents of the source. If the contents are `null` the override is removed
@@ -937,6 +954,12 @@
   String name;
 
   /**
+   * Configuration data associated with this context.
+   */
+  final HashMap<ResultDescriptor, Object> _configurationData =
+      new HashMap<ResultDescriptor, Object>();
+
+  /**
    * The set of analysis options controlling the behavior of this context.
    */
   AnalysisOptionsImpl _options = new AnalysisOptionsImpl();
@@ -1568,6 +1591,11 @@
   }
 
   @override
+  List<newContext.WorkManager> get workManagers {
+    throw new NotImplementedException('In not task-based AnalysisContext.');
+  }
+
+  @override
   void addListener(AnalysisListener listener) {
     if (!_listeners.contains(listener)) {
       _listeners.add(listener);
@@ -1934,6 +1962,9 @@
   }
 
   @override
+  Object getConfigurationData(ResultDescriptor key) => _configurationData[key];
+
+  @override
   TimestampedData<String> getContents(Source source) {
     String contents = _contentCache.getContents(source);
     if (contents != null) {
@@ -2630,6 +2661,11 @@
   }
 
   @override
+  void setConfigurationData(ResultDescriptor key, Object data) {
+    _configurationData[key] = data;
+  }
+
+  @override
   void setContents(Source source, String contents) {
     _contentsChanged(source, contents, true);
   }
@@ -5840,6 +5876,11 @@
   static const String SUFFIX_HTML = "html";
 
   /**
+   * The file name used for analysis options files.
+   */
+  static const String ANALYSIS_OPTIONS_FILE = '.analysis_options';
+
+  /**
    * The unique instance of this class.
    */
   static final AnalysisEngine instance = new AnalysisEngine._();
@@ -6008,6 +6049,18 @@
   }
 
   /**
+   * Return `true` if the given [fileName] is an analysis options file.
+   */
+  static bool isAnalysisOptionsFileName(String fileName,
+      [pathos.Context context]) {
+    if (fileName == null) {
+      return false;
+    }
+    return (context ?? pathos.posix).basename(fileName) ==
+        ANALYSIS_OPTIONS_FILE;
+  }
+
+  /**
    * Return `true` if the given [fileName] is assumed to contain Dart source
    * code.
    */
@@ -9395,6 +9448,11 @@
   TypeResolverVisitorFactory get typeResolverVisitorFactory;
 
   /**
+   * A list of all [WorkManager]s used by this context.
+   */
+  List<newContext.WorkManager> get workManagers;
+
+  /**
    * Return a list containing the sources of the libraries that are exported by
    * the library with the given [source]. The list will be empty if the given
    * source is invalid, if the given source does not represent a library, or if
diff --git a/packages/analyzer/lib/src/generated/incremental_resolver.dart b/packages/analyzer/lib/src/generated/incremental_resolver.dart
index 86a87bd..4a8dada 100644
--- a/packages/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/packages/analyzer/lib/src/generated/incremental_resolver.dart
@@ -921,6 +921,7 @@
         isByTask(ResolveUnitTask.DESCRIPTOR) ||
         isByTask(ResolveUnitTypeNamesTask.DESCRIPTOR) ||
         isByTask(ResolveVariableReferencesTask.DESCRIPTOR) ||
+        isByTask(StrongModeVerifyUnitTask.DESCRIPTOR) ||
         isByTask(VerifyUnitTask.DESCRIPTOR)) {
       return DeltaResult.KEEP_CONTINUE;
     }
@@ -1245,6 +1246,7 @@
     _shiftErrors_NEW(LIBRARY_UNIT_ERRORS);
     _shiftErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS);
     _shiftErrors_NEW(RESOLVE_UNIT_ERRORS);
+    _shiftErrors_NEW(STRONG_MODE_ERRORS);
     _shiftErrors_NEW(VARIABLE_REFERENCE_ERRORS);
     _shiftErrors_NEW(VERIFY_ERRORS);
   }
@@ -1316,6 +1318,7 @@
     _updateErrors_NEW(VARIABLE_REFERENCE_ERRORS, []);
     _updateErrors_NEW(VERIFY_ERRORS, _verifyErrors);
     // invalidate results we don't update incrementally
+    newUnitEntry.setState(STRONG_MODE_ERRORS, CacheState.INVALID);
     newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(HINTS, CacheState.INVALID);
diff --git a/packages/analyzer/lib/src/generated/parser.dart b/packages/analyzer/lib/src/generated/parser.dart
index 113da91..76f9dc7 100644
--- a/packages/analyzer/lib/src/generated/parser.dart
+++ b/packages/analyzer/lib/src/generated/parser.dart
@@ -4038,22 +4038,52 @@
         TokenType.INDEX
       ]);
     }
+    bool allowAdditionalTokens = true;
     // We know that we have an identifier, and need to see whether it might be
     // a type name.
+    if (_currentToken.type != TokenType.IDENTIFIER) {
+      allowAdditionalTokens = false;
+    }
     Token token = _skipTypeName(_currentToken);
     if (token == null) {
       // There was no type name, so this can't be a declaration.
       return false;
     }
+    if (token.type != TokenType.IDENTIFIER) {
+      allowAdditionalTokens = false;
+    }
     token = _skipSimpleIdentifier(token);
     if (token == null) {
       return false;
     }
     TokenType type = token.type;
-    return type == TokenType.EQ ||
+    // Usual cases in valid code:
+    //     String v = '';
+    //     String v, v2;
+    //     String v;
+    //     for (String item in items) {}
+    if (type == TokenType.EQ ||
         type == TokenType.COMMA ||
         type == TokenType.SEMICOLON ||
-        _tokenMatchesKeyword(token, Keyword.IN);
+        _tokenMatchesKeyword(token, Keyword.IN)) {
+      return true;
+    }
+    // It is OK to parse as a variable declaration in these cases:
+    //     String v }
+    //     String v if (true) print('OK');
+    //     String v { print(42); }
+    // ...but not in these cases:
+    //     get getterName {
+    //     String get getterName
+    if (allowAdditionalTokens) {
+      if (type == TokenType.CLOSE_CURLY_BRACKET ||
+          type == TokenType.KEYWORD ||
+          type == TokenType.IDENTIFIER ||
+          type == TokenType.OPEN_CURLY_BRACKET) {
+        return true;
+      }
+    }
+    return false;
   }
 
   bool _isLikelyParameterList() {
@@ -5829,12 +5859,12 @@
         _reportErrorForToken(
             ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
       }
-      Token leftSeparator = _expect(TokenType.SEMICOLON);
+      Token leftSeparator = _expectSemicolon();
       Expression condition = null;
       if (!_matches(TokenType.SEMICOLON)) {
         condition = parseExpression2();
       }
-      Token rightSeparator = _expect(TokenType.SEMICOLON);
+      Token rightSeparator = _expectSemicolon();
       List<Expression> updaters = null;
       if (!_matches(TokenType.CLOSE_PAREN)) {
         updaters = _parseExpressionList();
@@ -8281,8 +8311,7 @@
    */
   Token _skipSimpleIdentifier(Token startToken) {
     if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
-        (_tokenMatches(startToken, TokenType.KEYWORD) &&
-            (startToken as KeywordToken).keyword.isPseudoKeyword)) {
+        _tokenMatchesPseudoKeyword(startToken)) {
       return startToken.next;
     }
     return null;
@@ -8506,8 +8535,7 @@
    */
   bool _tokenMatchesIdentifier(Token token) =>
       _tokenMatches(token, TokenType.IDENTIFIER) ||
-          (_tokenMatches(token, TokenType.KEYWORD) &&
-              (token as KeywordToken).keyword.isPseudoKeyword);
+          _tokenMatchesPseudoKeyword(token);
 
   /**
    * Return `true` if the given [token] matches the given [keyword].
@@ -8517,6 +8545,13 @@
           (token as KeywordToken).keyword == keyword;
 
   /**
+   * Return `true` if the given [token] matches a pseudo keyword.
+   */
+  bool _tokenMatchesPseudoKeyword(Token token) =>
+      _tokenMatches(token, TokenType.KEYWORD) &&
+          (token as KeywordToken).keyword.isPseudoKeyword;
+
+  /**
    * Return `true` if the given [token] matches the given [identifier].
    */
   bool _tokenMatchesString(Token token, String identifier) =>
diff --git a/packages/analyzer/lib/src/generated/resolver.dart b/packages/analyzer/lib/src/generated/resolver.dart
index a5b2e92..47a68ee 100644
--- a/packages/analyzer/lib/src/generated/resolver.dart
+++ b/packages/analyzer/lib/src/generated/resolver.dart
@@ -1521,14 +1521,14 @@
       if (!_isDebugConstant(lhsCondition)) {
         EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition);
         if (lhsResult != null) {
-          if (lhsResult.value.isTrue && isBarBar) {
+          if (lhsResult.value.toBoolValue() == true && isBarBar) {
             // report error on else block: true || !e!
             _errorReporter.reportErrorForNode(
                 HintCode.DEAD_CODE, node.rightOperand);
             // only visit the LHS:
             _safelyVisit(lhsCondition);
             return null;
-          } else if (lhsResult.value.isFalse && isAmpAmp) {
+          } else if (lhsResult.value.toBoolValue() == false && isAmpAmp) {
             // report error on if block: false && !e!
             _errorReporter.reportErrorForNode(
                 HintCode.DEAD_CODE, node.rightOperand);
@@ -1582,7 +1582,7 @@
       EvaluationResultImpl result =
           _getConstantBooleanValue(conditionExpression);
       if (result != null) {
-        if (result.value.isTrue) {
+        if (result.value.toBoolValue() == true) {
           // report error on else block: true ? 1 : !2!
           _errorReporter.reportErrorForNode(
               HintCode.DEAD_CODE, node.elseExpression);
@@ -1608,7 +1608,7 @@
       EvaluationResultImpl result =
           _getConstantBooleanValue(conditionExpression);
       if (result != null) {
-        if (result.value.isTrue) {
+        if (result.value.toBoolValue() == true) {
           // report error on else block: if(true) {} else {!}
           Statement elseStatement = node.elseStatement;
           if (elseStatement != null) {
@@ -1717,7 +1717,7 @@
       EvaluationResultImpl result =
           _getConstantBooleanValue(conditionExpression);
       if (result != null) {
-        if (result.value.isFalse) {
+        if (result.value.toBoolValue() == false) {
           // report error on if block: while (false) {!}
           _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body);
           return null;
@@ -3234,6 +3234,9 @@
         variable = new TopLevelVariableElementImpl.forNode(variableName);
       }
       element = variable;
+      if (node.parent.parent is TopLevelVariableDeclaration) {
+        _setDocRange(element, node.parent.parent);
+      }
       if ((node.parent as VariableDeclarationList).type == null) {
         variable.hasImplicitType = true;
       }
@@ -14419,11 +14422,11 @@
       PropertyInducingElementImpl variable =
           accessor.variable as PropertyInducingElementImpl;
       if (accessor.isGetter) {
-        variable.type = type.returnType;
+        variable.type = type.baseReturnType;
       } else if (variable.type == null) {
-        List<DartType> parameterTypes = type.normalParameterTypes;
-        if (parameterTypes != null && parameterTypes.length > 0) {
-          variable.type = parameterTypes[0];
+        List<ParameterElement> parameters = type.baseParameters;
+        if (parameters != null && parameters.length > 0) {
+          variable.type = parameters[0].type;
         }
       }
     }
@@ -15721,11 +15724,20 @@
   @override
   Object visitSimpleIdentifier(SimpleIdentifier node) {
     // Ignore if already resolved - declaration or type.
-    if (node.staticElement != null) {
+    if (node.inDeclarationContext()) {
+      return null;
+    }
+    // Ignore if it cannot be a reference to a local variable.
+    AstNode parent = node.parent;
+    if (parent is FieldFormalParameter) {
+      return null;
+    } else if (parent is ConstructorDeclaration && parent.returnType == node) {
+      return null;
+    } else if (parent is ConstructorFieldInitializer &&
+        parent.fieldName == node) {
       return null;
     }
     // Ignore if qualified.
-    AstNode parent = node.parent;
     if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
       return null;
     }
@@ -15775,6 +15787,11 @@
     }
     return null;
   }
+
+  @override
+  Object visitTypeName(TypeName node) {
+    return null;
+  }
 }
 
 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor {
diff --git a/packages/analyzer/lib/src/generated/sdk.dart b/packages/analyzer/lib/src/generated/sdk.dart
index 1bf502b..c4f034f 100644
--- a/packages/analyzer/lib/src/generated/sdk.dart
+++ b/packages/analyzer/lib/src/generated/sdk.dart
@@ -145,7 +145,7 @@
    * The name of the optional parameter used to specify the category of the
    * library.
    */
-  static String _CATEGORY = "category";
+  static String _CATEGORIES = "categories";
 
   /**
    * The name of the optional parameter used to specify the platforms on which
@@ -183,6 +183,20 @@
    */
   LibraryMap get librariesMap => _librariesMap;
 
+
+  // To be backwards-compatible the new categories field is translated to
+  // an old approximation.
+  String convertCategories(String categories) {
+    switch (categories) {
+      case "": return "Internal";
+      case "Client": return "Client";
+      case "Server": return "Server";
+      case "Client,Server": return "Shared";
+      case "Client,Server,Embedded": return "Shared";
+    }
+    return "Shared";
+  }
+
   @override
   Object visitMapLiteralEntry(MapLiteralEntry node) {
     String libraryName = null;
@@ -200,8 +214,9 @@
         } else if (argument is NamedExpression) {
           String name = argument.name.label.name;
           Expression expression = argument.expression;
-          if (name == _CATEGORY) {
-            library.category = (expression as SimpleStringLiteral).value;
+          if (name == _CATEGORIES) {
+            library.category =
+                convertCategories((expression as StringLiteral).stringValue);
           } else if (name == _IMPLEMENTATION) {
             library.implementation = (expression as BooleanLiteral).value;
           } else if (name == _DOCUMENTED) {
diff --git a/packages/analyzer/lib/src/generated/static_type_analyzer.dart b/packages/analyzer/lib/src/generated/static_type_analyzer.dart
index 7362c4d..ce0016c 100644
--- a/packages/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/packages/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -1419,12 +1419,17 @@
   }
 
   // TODO(vsm): Use leafp's matchType here?
-  DartType _findIteratedType(InterfaceType type, DartType targetType) {
+  DartType _findIteratedType(DartType type, DartType targetType) {
     // Set by _find if match is found
     DartType result = null;
     // Elements we've already visited on a given inheritance path.
     HashSet<ClassElement> visitedClasses = null;
 
+    while (type is TypeParameterType) {
+      TypeParameterElement element = type.element;
+      type = element.bound;
+    }
+
     bool _find(InterfaceType type) {
       ClassElement element = type.element;
       if (type == _typeProvider.objectType || element == null) {
@@ -1451,7 +1456,9 @@
         visitedClasses.remove(element);
       }
     }
-    _find(type);
+    if (type is InterfaceType) {
+      _find(type);
+    }
     return result;
   }
 
@@ -1691,15 +1698,13 @@
         Expression expr = loop.iterable;
         LocalVariableElementImpl element = loopVariable.element;
         DartType exprType = expr.staticType;
-        if (exprType is InterfaceType) {
-          DartType targetType = (loop.awaitKeyword == null)
-              ? _typeProvider.iterableType
+        DartType targetType = (loop.awaitKeyword == null)
+          ? _typeProvider.iterableType
               : _typeProvider.streamType;
-          DartType iteratedType = _findIteratedType(exprType, targetType);
-          if (element != null && iteratedType != null) {
-            element.type = iteratedType;
-            loopVariable.identifier.staticType = iteratedType;
-          }
+        DartType iteratedType = _findIteratedType(exprType, targetType);
+        if (element != null && iteratedType != null) {
+          element.type = iteratedType;
+          loopVariable.identifier.staticType = iteratedType;
         }
       }
     }
diff --git a/packages/analyzer/lib/src/plugin/engine_plugin.dart b/packages/analyzer/lib/src/plugin/engine_plugin.dart
index 6573b0a..a53deb8 100644
--- a/packages/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/packages/analyzer/lib/src/plugin/engine_plugin.dart
@@ -99,21 +99,24 @@
    * Return a list containing all of the contributed analysis error result
    * descriptors for Dart sources.
    */
-  List<TaskDescriptor> get dartErrorsForSource =>
+  @ExtensionPointId('DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID')
+  List<ResultDescriptor> get dartErrorsForSource =>
       dartErrorsForSourceExtensionPoint.extensions;
 
   /**
    * Return a list containing all of the contributed analysis error result
    * descriptors for Dart library specific units.
    */
-  List<TaskDescriptor> get dartErrorsForUnit =>
+  @ExtensionPointId('DART_ERRORS_FOR_UNIT_EXTENSION_POINT_ID')
+  List<ResultDescriptor> get dartErrorsForUnit =>
       dartErrorsForUnitExtensionPoint.extensions;
 
   /**
    * Return a list containing all of the contributed analysis error result
    * descriptors for HTML sources.
    */
-  List<TaskDescriptor> get htmlErrors => htmlErrorsExtensionPoint.extensions;
+  @ExtensionPointId('HTML_ERRORS_EXTENSION_POINT_ID')
+  List<ResultDescriptor> get htmlErrors => htmlErrorsExtensionPoint.extensions;
 
   /**
    * Return a list containing all of the task descriptors that were contributed.
@@ -158,19 +161,17 @@
   }
 
   void _registerDartErrorsForSource(RegisterExtension registerExtension) {
-    String id = DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID;
-    registerExtension(id, PARSE_ERRORS);
-    registerExtension(id, SCAN_ERRORS);
+    registerExtension(DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID, PARSE_ERRORS);
+    registerExtension(DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID, SCAN_ERRORS);
   }
 
   void _registerDartErrorsForUnit(RegisterExtension registerExtension) {
-    String id = DART_ERRORS_FOR_UNIT_EXTENSION_POINT_ID;
-    registerExtension(id, LIBRARY_UNIT_ERRORS);
+    registerExtension(
+        DART_ERRORS_FOR_UNIT_EXTENSION_POINT_ID, LIBRARY_UNIT_ERRORS);
   }
 
   void _registerHtmlErrors(RegisterExtension registerExtension) {
-    String id = HTML_ERRORS_EXTENSION_POINT_ID;
-    registerExtension(id, HTML_DOCUMENT_ERRORS);
+    registerExtension(HTML_ERRORS_EXTENSION_POINT_ID, HTML_DOCUMENT_ERRORS);
   }
 
   void _registerTaskExtensions(RegisterExtension registerExtension) {
@@ -217,6 +218,7 @@
     registerExtension(taskId, ResolveUnitTypeNamesTask.DESCRIPTOR);
     registerExtension(taskId, ResolveVariableReferencesTask.DESCRIPTOR);
     registerExtension(taskId, ScanDartTask.DESCRIPTOR);
+    registerExtension(taskId, StrongModeVerifyUnitTask.DESCRIPTOR);
     registerExtension(taskId, VerifyUnitTask.DESCRIPTOR);
     //
     // Register HTML tasks.
@@ -270,3 +272,17 @@
     }
   }
 }
+
+/**
+ * Annotation describing the relationship between a getter in [EnginePlugin]
+ * and the associated identifier (in '../../plugin/task.dart') which can be
+ * passed to the extension manager to populate it.
+ *
+ * This annotation is not used at runtime; it is used to aid in static analysis
+ * of the task model during development.
+ */
+class ExtensionPointId {
+  final String extensionPointId;
+
+  const ExtensionPointId(this.extensionPointId);
+}
diff --git a/packages/analyzer/lib/src/plugin/options_plugin.dart b/packages/analyzer/lib/src/plugin/options_plugin.dart
index fc82910..3fb5e91 100644
--- a/packages/analyzer/lib/src/plugin/options_plugin.dart
+++ b/packages/analyzer/lib/src/plugin/options_plugin.dart
@@ -23,7 +23,9 @@
 
   /// All contributed options processors.
   List<OptionsProcessor> get optionsProcessors =>
-      optionsProcessorExtensionPoint.extensions;
+      optionsProcessorExtensionPoint == null
+          ? const []
+          : optionsProcessorExtensionPoint.extensions;
 
   @override
   String get uniqueIdentifier => UNIQUE_IDENTIFIER;
diff --git a/packages/analyzer/lib/src/services/lint.dart b/packages/analyzer/lib/src/services/lint.dart
index 5efc3ea..a6b55cc 100644
--- a/packages/analyzer/lib/src/services/lint.dart
+++ b/packages/analyzer/lib/src/services/lint.dart
@@ -9,11 +9,25 @@
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/visitors.dart';
+import 'package:analyzer/src/task/model.dart';
+import 'package:analyzer/task/model.dart';
 
-/// A registry containing mappings of contexts to their associated configured
-/// lints.
-final Map<AnalysisContext, List<Linter>> lintRegistry =
-    <AnalysisContext, List<Linter>>{};
+const List<Linter> _noLints = const <Linter>[];
+
+/// The descriptor used to associate lints with analysis contexts in
+/// configuration data.
+final ResultDescriptor<List<Linter>> CONFIGURED_LINTS_KEY =
+    new ResultDescriptorImpl('configured.lints', _noLints);
+
+/// Return lints associated with this [context], or an empty list if there are
+/// none.
+List<Linter> getLints(AnalysisContext context) =>
+    context.getConfigurationData(CONFIGURED_LINTS_KEY) ?? _noLints;
+
+/// Associate these [lints] with the given [context].
+void setLints(AnalysisContext context, List<Linter> lints) {
+  context.setConfigurationData(CONFIGURED_LINTS_KEY, lints);
+}
 
 /// Implementers contribute lint warnings via the provided error [reporter].
 abstract class Linter {
@@ -32,9 +46,7 @@
 ///
 /// See [LintCode].
 class LintGenerator {
-  /// A global container for contributed linters.
-  @deprecated // Use lintRegistry.
-  static final List<Linter> LINTERS = <Linter>[];
+  static const List<Linter> _noLints = const <Linter>[];
 
   final Iterable<CompilationUnit> _compilationUnits;
   final AnalysisErrorListener _errorListener;
@@ -42,7 +54,7 @@
 
   LintGenerator(this._compilationUnits, this._errorListener,
       [Iterable<Linter> linters])
-      : _linters = linters ?? LINTERS;
+      : _linters = linters ?? _noLints;
 
   void generate() {
     PerformanceStatistics.lint.makeCurrentWhile(() {
diff --git a/packages/analyzer/lib/src/task/dart.dart b/packages/analyzer/lib/src/task/dart.dart
index 81745f7..b87f776 100644
--- a/packages/analyzer/lib/src/task/dart.dart
+++ b/packages/analyzer/lib/src/task/dart.dart
@@ -29,6 +29,8 @@
 import 'package:analyzer/src/task/html.dart';
 import 'package:analyzer/src/task/inputs.dart';
 import 'package:analyzer/src/task/model.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:analyzer/src/task/strong/rules.dart';
 import 'package:analyzer/src/task/strong_mode.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/general.dart';
@@ -160,43 +162,6 @@
     new ListResultDescriptor<Source>('IMPORT_EXPORT_SOURCE_CLOSURE', null);
 
 /**
- * A list of the [LibraryElement]s that make up the strongly connected
- * component in the import/export graph in which the target resides.
- *
- * Only non-empty in strongMode
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ListResultDescriptor<LibraryElement> LIBRARY_CYCLE =
-    new ListResultDescriptor<LibraryElement>('LIBRARY_CYCLE', null);
-
-/**
- * A list of the [CompilationUnitElement]s (including all parts) that make up
- * the strongly connected component in the import/export graph in which the
- * target resides.
- *
- * Only non-empty in strongMode
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ListResultDescriptor<CompilationUnitElement> LIBRARY_CYCLE_UNITS =
-    new ListResultDescriptor<CompilationUnitElement>(
-        'LIBRARY_CYCLE_UNITS', null);
-
-/**
- * A list of the [CompilationUnitElement]s that comprise all of the parts and
- * libraries in the direct import/export dependencies of the library cycle
- * of the target, with the intra-component dependencies excluded.
- *
- * Only non-empty in strongMode
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ListResultDescriptor<CompilationUnitElement> LIBRARY_CYCLE_DEPENDENCIES =
-    new ListResultDescriptor<CompilationUnitElement>(
-        'LIBRARY_CYCLE_DEPENDENCIES', null);
-
-/**
  * A list of the [VariableElement]s whose type should be inferred that another
  * inferable static variable (the target) depends on.
  *
@@ -232,6 +197,43 @@
         cachingPolicy: ELEMENT_CACHING_POLICY);
 
 /**
+ * A list of the [LibraryElement]s that make up the strongly connected
+ * component in the import/export graph in which the target resides.
+ *
+ * Only non-empty in strongMode.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<LibraryElement> LIBRARY_CYCLE =
+    new ListResultDescriptor<LibraryElement>('LIBRARY_CYCLE', null);
+
+/**
+ * A list of the [CompilationUnitElement]s that comprise all of the parts and
+ * libraries in the direct import/export dependencies of the library cycle
+ * of the target, with the intra-component dependencies excluded.
+ *
+ * Only non-empty in strongMode.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<CompilationUnitElement> LIBRARY_CYCLE_DEPENDENCIES =
+    new ListResultDescriptor<CompilationUnitElement>(
+        'LIBRARY_CYCLE_DEPENDENCIES', null);
+
+/**
+ * A list of the [CompilationUnitElement]s (including all parts) that make up
+ * the strongly connected component in the import/export graph in which the
+ * target resides.
+ *
+ * Only non-empty in strongMode.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<CompilationUnitElement> LIBRARY_CYCLE_UNITS =
+    new ListResultDescriptor<CompilationUnitElement>(
+        'LIBRARY_CYCLE_UNITS', null);
+
+/**
  * The partial [LibraryElement] associated with a library.
  *
  * The [LibraryElement] and its [CompilationUnitElement]s are attached to each
@@ -341,17 +343,6 @@
     new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null);
 
 /**
- * The errors produced while resolving a full compilation unit.
- *
- * The list will be empty if there were no errors, but will not be `null`.
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ListResultDescriptor<AnalysisError> RESOLVE_UNIT_ERRORS =
-    new ListResultDescriptor<AnalysisError>(
-        'RESOLVE_UNIT_ERRORS', AnalysisError.NO_ERRORS);
-
-/**
  * The errors produced while resolving type names.
  *
  * The list will be empty if there were no errors, but will not be `null`.
@@ -363,9 +354,22 @@
         'RESOLVE_TYPE_NAMES_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
- * The partially resolved [CompilationUnit] associated with a unit.
+ * The errors produced while resolving a full compilation unit.
  *
- * All declarations bound to the element defined by the declaration.
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> RESOLVE_UNIT_ERRORS =
+    new ListResultDescriptor<AnalysisError>(
+        'RESOLVE_UNIT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * Tasks that use this value as an input can assume that the [SimpleIdentifier]s
+ * at all declaration sites have been bound to the element defined by the
+ * declaration, except for the constants defined in an 'enum' declaration.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -374,9 +378,21 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The partially resolved [CompilationUnit] associated with a unit.
+ * The resolved [CompilationUnit] associated with a compilation unit, with
+ * constants resolved.
  *
- * All the enum member elements are built.
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT10 =
+    new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT10', null,
+        cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * Tasks that use this value as an input can assume that the [SimpleIdentifier]s
+ * at all declaration sites have been bound to the element defined by the
+ * declaration, including the constants defined in an 'enum' declaration.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -385,9 +401,12 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The partially resolved [CompilationUnit] associated with a unit.
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
  *
- * [RESOLVED_UNIT2] with resolved type names.
+ * In addition to what is true of a [RESOLVED_UNIT2], tasks that use this value
+ * as an input can assume that the types associated with declarations have been
+ * resolved. This includes the types of superclasses, mixins, interfaces,
+ * fields, return types, parameters, and local variables.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -396,9 +415,11 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The partially resolved [CompilationUnit] associated with a unit.
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
  *
- * [RESOLVED_UNIT3] plus resolved local variables and formal parameters.
+ * In addition to what is true of a [RESOLVED_UNIT3], tasks that use this value
+ * as an input can assume that references to local variables and formal
+ * parameters have been resolved.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -407,9 +428,12 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The resolved [CompilationUnit] associated with a compilation unit in which
- * elements and types have been initially resolved outside of method bodies in
- * addition to everything that is true of a [RESOLVED_UNIT4].
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * In addition to what is true of a [RESOLVED_UNIT4], tasks that use this value
+ * as an input can assume that elements and types associated with expressions
+ * outside of method bodies (essentially initializers) have been initially
+ * resolved.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -418,9 +442,10 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The resolved [CompilationUnit] associated with a compilation unit in which
- * the types of static variables have been inferred in addition to everything
- * that is true of a [RESOLVED_UNIT5].
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * In addition to what is true of a [RESOLVED_UNIT5], tasks that use this value
+ * as an input can assume that the types of static variables have been inferred.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -429,9 +454,11 @@
         cachingPolicy: AST_CACHING_POLICY);
 
 /**
- * The resolved [CompilationUnit] associated with a compilation unit in which
- * the right hand sides of instance variables have been re-resolved in addition
- * to everything that is true of a [RESOLVED_UNIT6].
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * In addition to what is true of a [RESOLVED_UNIT6], tasks that use this value
+ * as an input can assume that the initializers of instance variables have been
+ * re-resolved.
  *
  * The result is only available for [LibrarySpecificUnit]s.
  */
@@ -472,6 +499,20 @@
         'SCAN_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * The additional strong mode errors produced while verifying a
+ * compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnits]s representing a
+ * compilation unit.
+ *
+ */
+final ListResultDescriptor<AnalysisError> STRONG_MODE_ERRORS =
+    new ListResultDescriptor<AnalysisError>(
+        'STRONG_MODE_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
  * The [TypeProvider] of the [AnalysisContext].
  */
 final ResultDescriptor<TypeProvider> TYPE_PROVIDER =
@@ -2109,7 +2150,7 @@
 }
 
 /**
- * A task that builds [RESOLVED_UNIT] for a unit.
+ * A task that builds [RESOLVED_UNIT10] for a unit.
  */
 class EvaluateUnitConstantsTask extends SourceBasedAnalysisTask {
   /**
@@ -2129,7 +2170,7 @@
       'EvaluateUnitConstantsTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT]);
+      <ResultDescriptor>[RESOLVED_UNIT10]);
 
   EvaluateUnitConstantsTask(AnalysisContext context, LibrarySpecificUnit target)
       : super(context, target);
@@ -2142,7 +2183,7 @@
     // No actual work needs to be performed; the task manager will ensure that
     // all constants are evaluated before this method is called.
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
-    outputs[RESOLVED_UNIT] = unit;
+    outputs[RESOLVED_UNIT10] = unit;
   }
 
   /**
@@ -2535,26 +2576,11 @@
  */
 class GenerateLintsTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [RESOLVED_UNIT8] input.
+   * The name of the [RESOLVED_UNIT] input.
    */
   static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
 
   /**
-   * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input.
-   */
-  static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS';
-
-  /**
-   * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input.
-   */
-  static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS';
-
-  /**
-   * The name of the [TYPE_PROVIDER] input.
-   */
-  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
-
-  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -2587,9 +2613,9 @@
     //
     // Generate lints.
     //
-    LintGenerator.LINTERS.forEach((l) => l.reporter = errorReporter);
-    Iterable<AstVisitor> visitors =
-        LintGenerator.LINTERS.map((l) => l.getVisitor()).toList();
+    List<Linter> linters = getLints(context);
+    linters.forEach((l) => l.reporter = errorReporter);
+    Iterable<AstVisitor> visitors = linters.map((l) => l.getVisitor()).toList();
     unit.accept(new DelegatingAstVisitor(visitors.where((v) => v != null)));
 
     //
@@ -2710,122 +2736,6 @@
 }
 
 /**
- * A task that ensures that all of the inferrable instance members in a
- * compilation unit have had their right hand sides re-resolved
- */
-class ResolveInstanceFieldsInUnitTask extends SourceBasedAnalysisTask {
-  /**
-   * The name of the [LIBRARY_ELEMENT5] input.
-   */
-  static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
-
-  /**
-   * The name of the [TYPE_PROVIDER] input.
-   */
-  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
-
-  /**
-   * The name of the input whose value is the [RESOLVED_UNIT6] for the
-   * compilation unit.
-   */
-  static const String UNIT_INPUT = 'UNIT_INPUT';
-
-  /**
-   * The task descriptor describing this kind of task.
-   */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ResolveInstanceFieldsInUnitTask',
-      createTask,
-      buildInputs,
-      <ResultDescriptor>[RESOLVED_UNIT7]);
-
-  /**
-   * Initialize a newly created task to build a library element for the given
-   * [unit] in the given [context].
-   */
-  ResolveInstanceFieldsInUnitTask(
-      InternalAnalysisContext context, LibrarySpecificUnit unit)
-      : super(context, unit);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  void internalPerform() {
-    //
-    // Prepare inputs.
-    //
-    LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
-    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
-    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
-
-    CompilationUnitElement unitElement = unit.element;
-    if (context.analysisOptions.strongMode) {
-      //
-      // Resolve references.
-      //
-      // TODO(leafp): This code only needs to re-resolve the right hand sides of
-      // instance fields.  We could do incremental resolution on each field
-      // only using the incremental resolver.  However, this caused a massive
-      // performance degredation on the large_class_declaration_test.dart test.
-      // I would hypothesize that incremental resolution of field is linear in
-      // the size of the enclosing class, and hence incrementally resolving each
-      // field was quadratic.  We may wish to revisit this if we can resolve
-      // this performance issue.
-      InheritanceManager inheritanceManager =
-          new InheritanceManager(libraryElement);
-      PartialResolverVisitor visitor = new PartialResolverVisitor(
-          libraryElement,
-          unitElement.source,
-          typeProvider,
-          AnalysisErrorListener.NULL_LISTENER,
-          inheritanceManager: inheritanceManager);
-      unit.accept(visitor);
-    }
-    //
-    // Record outputs.
-    //
-    outputs[RESOLVED_UNIT7] = unit;
-  }
-
-  /**
-   * Return a map from the names of the inputs of this kind of task to the task
-   * input descriptors describing those inputs for a task with the given
-   * [libSource].
-   */
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    LibrarySpecificUnit unit = target;
-    return <String, TaskInput>{
-      UNIT_INPUT: RESOLVED_UNIT6.of(unit),
-      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
-      TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
-      // In strong mode, add additional dependencies to enforce inference
-      // ordering.
-
-      // Require that static variable inference  be complete for all units in
-      // the current library cycle.
-      'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT6
-              .of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
-      // Require that full inference be complete for all dependencies of the
-      // current library cycle.
-      'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
-          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
-              .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
-    };
-  }
-
-  /**
-   * Create a [ResolveInstanceFieldsInUnitTask] based on the given [target] in
-   * the given [context].
-   */
-  static ResolveInstanceFieldsInUnitTask createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new ResolveInstanceFieldsInUnitTask(context, target);
-  }
-}
-
-/**
  * An abstract class that defines utility methods that are useful for tasks
  * operating on static variables.
  */
@@ -3138,6 +3048,11 @@
   static const String LINTS_INPUT = 'LINTS';
 
   /**
+   * The name of the [STRONG_MODE_ERRORS] input.
+   */
+  static const String STRONG_MODE_ERRORS_INPUT = 'STRONG_MODE_ERRORS';
+
+  /**
    * The name of the [RESOLVE_TYPE_NAMES_ERRORS] input.
    */
   static const String RESOLVE_TYPE_NAMES_ERRORS_INPUT =
@@ -3186,6 +3101,7 @@
     errorLists.add(getRequiredInput(LINTS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_UNIT_ERRORS_INPUT));
+    errorLists.add(getRequiredInput(STRONG_MODE_ERRORS_INPUT));
     errorLists.add(getRequiredInput(VARIABLE_REFERENCE_ERRORS_INPUT));
     errorLists.add(getRequiredInput(VERIFY_ERRORS_INPUT));
     //
@@ -3206,6 +3122,7 @@
       LINTS_INPUT: LINTS.of(unit),
       RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit),
       RESOLVE_UNIT_ERRORS_INPUT: RESOLVE_UNIT_ERRORS.of(unit),
+      STRONG_MODE_ERRORS_INPUT: STRONG_MODE_ERRORS.of(unit),
       VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
       VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
     };
@@ -3234,7 +3151,9 @@
 }
 
 /**
- * A task that parses the content of a Dart file, producing an AST structure.
+ * A task that parses the content of a Dart file, producing an AST structure,
+ * any lexical errors found in the process, the kind of the file (library or
+ * part), and several lists based on the AST.
  */
 class ParseDartTask extends SourceBasedAnalysisTask {
   /**
@@ -3465,10 +3384,10 @@
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
     CompilationUnitElement unitElement = unit.element;
     TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    //
+    // Resolve references and record outputs.
+    //
     if (context.analysisOptions.strongMode) {
-      //
-      // Resolve references.
-      //
       InheritanceManager inheritanceManager =
           new InheritanceManager(libraryElement);
       PartialResolverVisitor visitor = new PartialResolverVisitor(
@@ -3478,9 +3397,7 @@
           AnalysisErrorListener.NULL_LISTENER,
           inheritanceManager: inheritanceManager);
       unit.accept(visitor);
-      //
-      // Record outputs.
-      //
+
       outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.variablesAndFields;
     } else {
       outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = [];
@@ -3661,12 +3578,12 @@
 }
 
 /**
- * A task that resolves the bodies of top-level functions, constructors, and
- * methods within a single compilation unit.
+ * A task that ensures that all of the inferrable instance members in a
+ * compilation unit have had their right hand sides re-resolved
  */
-class ResolveUnitTask extends SourceBasedAnalysisTask {
+class ResolveInstanceFieldsInUnitTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the input whose value is the defining [LIBRARY_ELEMENT5].
+   * The name of the [LIBRARY_ELEMENT5] input.
    */
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
@@ -3676,19 +3593,27 @@
   static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
 
   /**
-   * The name of the [RESOLVED_UNIT8] input.
+   * The name of the input whose value is the [RESOLVED_UNIT6] for the
+   * compilation unit.
    */
   static const String UNIT_INPUT = 'UNIT_INPUT';
 
+  /**
+   * The task descriptor describing this kind of task.
+   */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ResolveUnitTask',
+      'ResolveInstanceFieldsInUnitTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT9]);
+      <ResultDescriptor>[RESOLVED_UNIT7]);
 
-  ResolveUnitTask(
-      InternalAnalysisContext context, LibrarySpecificUnit compilationUnit)
-      : super(context, compilationUnit);
+  /**
+   * Initialize a newly created task to build a library element for the given
+   * [unit] in the given [context].
+   */
+  ResolveInstanceFieldsInUnitTask(
+      InternalAnalysisContext context, LibrarySpecificUnit unit)
+      : super(context, unit);
 
   @override
   TaskDescriptor get descriptor => DESCRIPTOR;
@@ -3701,50 +3626,70 @@
     LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
     TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
-    //
-    // Resolve everything
-    //
+
     CompilationUnitElement unitElement = unit.element;
-    RecordingErrorListener errorListener = new RecordingErrorListener();
-    ResolverVisitor visitor = new ResolverVisitor(
-        libraryElement, unitElement.source, typeProvider, errorListener);
-    unit.accept(visitor);
+    if (context.analysisOptions.strongMode) {
+      //
+      // Resolve references.
+      //
+      // TODO(leafp): This code only needs to re-resolve the right hand sides of
+      // instance fields.  We could do incremental resolution on each field
+      // only using the incremental resolver.  However, this caused a massive
+      // performance degredation on the large_class_declaration_test.dart test.
+      // I would hypothesize that incremental resolution of field is linear in
+      // the size of the enclosing class, and hence incrementally resolving each
+      // field was quadratic.  We may wish to revisit this if we can resolve
+      // this performance issue.
+      InheritanceManager inheritanceManager =
+          new InheritanceManager(libraryElement);
+      PartialResolverVisitor visitor = new PartialResolverVisitor(
+          libraryElement,
+          unitElement.source,
+          typeProvider,
+          AnalysisErrorListener.NULL_LISTENER,
+          inheritanceManager: inheritanceManager);
+      unit.accept(visitor);
+    }
     //
     // Record outputs.
     //
-    outputs[RESOLVE_UNIT_ERRORS] = errorListener.errors;
-    outputs[RESOLVED_UNIT9] = unit;
+    outputs[RESOLVED_UNIT7] = unit;
   }
 
   /**
    * Return a map from the names of the inputs of this kind of task to the task
    * input descriptors describing those inputs for a task with the given
-   * [target].
+   * [libSource].
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
+      UNIT_INPUT: RESOLVED_UNIT6.of(unit),
       LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
-      UNIT_INPUT: RESOLVED_UNIT8.of(unit),
       // In strong mode, add additional dependencies to enforce inference
       // ordering.
 
-      // Require that inference be complete for all units in the
-      // current library cycle.
+      // Require that static variable inference  be complete for all units in
+      // the current library cycle.
       'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT6
+              .of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
+      // Require that full inference be complete for all dependencies of the
+      // current library cycle.
+      'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
           (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
               .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
     };
   }
 
   /**
-   * Create a [ResolveUnitTask] based on the given [target] in
+   * Create a [ResolveInstanceFieldsInUnitTask] based on the given [target] in
    * the given [context].
    */
-  static ResolveUnitTask createTask(
+  static ResolveInstanceFieldsInUnitTask createTask(
       AnalysisContext context, AnalysisTarget target) {
-    return new ResolveUnitTask(context, target);
+    return new ResolveInstanceFieldsInUnitTask(context, target);
   }
 }
 
@@ -3884,6 +3829,94 @@
 }
 
 /**
+ * A task that resolves the bodies of top-level functions, constructors, and
+ * methods within a single compilation unit.
+ */
+class ResolveUnitTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the input whose value is the defining [LIBRARY_ELEMENT5].
+   */
+  static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+  /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
+   * The name of the [RESOLVED_UNIT8] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ResolveUnitTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT9]);
+
+  ResolveUnitTask(
+      InternalAnalysisContext context, LibrarySpecificUnit compilationUnit)
+      : super(context, compilationUnit);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    //
+    // Prepare inputs.
+    //
+    LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    //
+    // Resolve everything.
+    //
+    CompilationUnitElement unitElement = unit.element;
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    ResolverVisitor visitor = new ResolverVisitor(
+        libraryElement, unitElement.source, typeProvider, errorListener);
+    unit.accept(visitor);
+    //
+    // Record outputs.
+    //
+    outputs[RESOLVE_UNIT_ERRORS] = errorListener.errors;
+    outputs[RESOLVED_UNIT9] = unit;
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the given
+   * [target].
+   */
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    LibrarySpecificUnit unit = target;
+    return <String, TaskInput>{
+      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
+      TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
+      UNIT_INPUT: RESOLVED_UNIT8.of(unit),
+      // In strong mode, add additional dependencies to enforce inference
+      // ordering.
+
+      // Require that inference be complete for all units in the
+      // current library cycle.
+      'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
+          (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+              .of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
+    };
+  }
+
+  /**
+   * Create a [ResolveUnitTask] based on the given [target] in
+   * the given [context].
+   */
+  static ResolveUnitTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ResolveUnitTask(context, target);
+  }
+}
+
+/**
  * A task that builds [RESOLVED_UNIT3] for a unit.
  */
 class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask {
@@ -3920,7 +3953,6 @@
 
   @override
   void internalPerform() {
-    RecordingErrorListener errorListener = new RecordingErrorListener();
     //
     // Prepare inputs.
     //
@@ -3931,6 +3963,7 @@
     //
     // Resolve TypeName nodes.
     //
+    RecordingErrorListener errorListener = new RecordingErrorListener();
     TypeResolverVisitor visitor = new TypeResolverVisitor(
         library, unitElement.source, typeProvider, errorListener);
     unit.accept(visitor);
@@ -3948,6 +3981,9 @@
    * given [target].
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    // TODO(brianwilkerson) This task updates the element model to have type
+    // information and updates the class hierarchy. It should produce a new
+    // version of the element model in order to record those changes.
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
       'importsExportNamespace':
@@ -4005,19 +4041,19 @@
 
   @override
   void internalPerform() {
-    RecordingErrorListener errorListener = new RecordingErrorListener();
     //
     // Prepare inputs.
     //
     LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
     CompilationUnitElement unitElement = unit.element;
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     //
     // Resolve local variables.
     //
-    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    RecordingErrorListener errorListener = new RecordingErrorListener();
     Scope nameScope = new LibraryScope(libraryElement, errorListener);
-    AstVisitor visitor = new VariableResolverVisitor(
+    VariableResolverVisitor visitor = new VariableResolverVisitor(
         libraryElement, unitElement.source, typeProvider, errorListener,
         nameScope: nameScope);
     unit.accept(visitor);
@@ -4054,7 +4090,8 @@
 }
 
 /**
- * A task that scans the content of a file, producing a set of Dart tokens.
+ * A task that scans the content of a Dart file, producing a stream of Dart
+ * tokens, line information, and any lexical errors encountered in the process.
  */
 class ScanDartTask extends SourceBasedAnalysisTask {
   /**
@@ -4166,6 +4203,84 @@
 }
 
 /**
+ * A task that builds [STRONG_MODE_ERRORS] for a unit.  Also builds
+ * [RESOLVED_UNIT] for a unit.
+ */
+class StrongModeVerifyUnitTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [RESOLVED_UNIT10] input.
+   */
+  static const String UNIT_INPUT = 'UNIT_INPUT';
+
+  /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'StrongModeVerifyUnitTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[STRONG_MODE_ERRORS, RESOLVED_UNIT]);
+
+  StrongModeVerifyUnitTask(
+      InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    //
+    // Prepare inputs.
+    //
+    TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+    CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+    if (context.analysisOptions.strongMode) {
+      unit.accept(new CodeChecker(new TypeRules(typeProvider), errorListener));
+    }
+
+    //
+    // Record outputs.
+    //
+    outputs[STRONG_MODE_ERRORS] = removeDuplicateErrors(errorListener.errors);
+    outputs[RESOLVED_UNIT] = unit;
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the
+   * given [target].
+   */
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    LibrarySpecificUnit unit = target;
+    return <String, TaskInput>{
+      'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
+          .of(unit.library)
+          .toMapOf(UNITS)
+          .toFlattenList((Source library, Source unit) =>
+              RESOLVED_UNIT10.of(new LibrarySpecificUnit(library, unit))),
+      UNIT_INPUT: RESOLVED_UNIT10.of(unit),
+      TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+    };
+  }
+
+  /**
+   * Create a [StrongModeVerifyUnitTask] based on the given [target] in
+   * the given [context].
+   */
+  static StrongModeVerifyUnitTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new StrongModeVerifyUnitTask(context, target);
+  }
+}
+
+/**
  * A task that builds [VERIFY_ERRORS] for a unit.
  */
 class VerifyUnitTask extends SourceBasedAnalysisTask {
@@ -4228,6 +4343,7 @@
         new InheritanceManager(libraryElement),
         context.analysisOptions.enableSuperMixins);
     unit.accept(errorVerifier);
+
     //
     // Record outputs.
     //
diff --git a/packages/analyzer/lib/src/task/dart_work_manager.dart b/packages/analyzer/lib/src/task/dart_work_manager.dart
index 7114053..61f92e5 100644
--- a/packages/analyzer/lib/src/task/dart_work_manager.dart
+++ b/packages/analyzer/lib/src/task/dart_work_manager.dart
@@ -46,6 +46,7 @@
     LIBRARY_UNIT_ERRORS,
     RESOLVE_TYPE_NAMES_ERRORS,
     RESOLVE_UNIT_ERRORS,
+    STRONG_MODE_ERRORS,
     VARIABLE_REFERENCE_ERRORS,
     VERIFY_ERRORS
   ];
@@ -193,6 +194,12 @@
    * Maybe empty, but not null.
    */
   List<Source> getLibrariesContainingPart(Source part) {
+    if (part.isInSystemLibrary) {
+      DartWorkManager sdkDartWorkManager = _getSdkDartWorkManager();
+      if (sdkDartWorkManager != this) {
+        return sdkDartWorkManager.getLibrariesContainingPart(part);
+      }
+    }
     List<Source> libraries = partLibrariesMap[part];
     return libraries != null ? libraries : Source.EMPTY_LIST;
   }
@@ -265,6 +272,14 @@
   void resultsComputed(
       AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs) {
     bool isDartSource = _isDartSource(target);
+    // Route SDK outputs to the SDK WorkManager.
+    if (isDartSource && target.source.isInSystemLibrary) {
+      DartWorkManager sdkWorkManager = _getSdkDartWorkManager();
+      if (sdkWorkManager != this) {
+        sdkWorkManager.resultsComputed(target, outputs);
+        return;
+      }
+    }
     // Organize sources.
     bool isDartLibrarySource = false;
     if (isDartSource) {
@@ -339,6 +354,22 @@
   }
 
   /**
+   * Return the SDK [DartWorkManager] or this one.
+   */
+  DartWorkManager _getSdkDartWorkManager() {
+    SourceFactory sourceFactory = context.sourceFactory;
+    InternalAnalysisContext sdkContext = sourceFactory.dartSdk.context;
+    if (sdkContext != context) {
+      for (WorkManager workManager in sdkContext.workManagers) {
+        if (workManager is DartWorkManager) {
+          return workManager;
+        }
+      }
+    }
+    return this;
+  }
+
+  /**
    * Invalidate all of the resolution results computed by this context. The flag
    * [invalidateUris] should be `true` if the cached results of converting URIs
    * to source files should also be invalidated.
diff --git a/packages/analyzer/lib/src/task/html.dart b/packages/analyzer/lib/src/task/html.dart
index 0ab546a..1804c50 100644
--- a/packages/analyzer/lib/src/task/html.dart
+++ b/packages/analyzer/lib/src/task/html.dart
@@ -322,6 +322,9 @@
       List<ParseError> parseErrors = parser.errors;
       List<AnalysisError> errors = <AnalysisError>[];
       for (ParseError parseError in parseErrors) {
+        if (parseError.errorCode == 'expected-doctype-but-got-start-tag') {
+          continue;
+        }
         SourceSpan span = parseError.span;
         errors.add(new AnalysisError(target.source, span.start.offset,
             span.length, HtmlErrorCode.PARSE_ERROR, [parseError.message]));
diff --git a/packages/analyzer/lib/src/task/strong/checker.dart b/packages/analyzer/lib/src/task/strong/checker.dart
new file mode 100644
index 0000000..9cfefe8
--- /dev/null
+++ b/packages/analyzer/lib/src/task/strong/checker.dart
@@ -0,0 +1,985 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
+// refactored to fit into analyzer.
+library analyzer.src.task.strong.checker;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
+
+import 'info.dart';
+import 'rules.dart';
+
+/// Checks for overriding declarations of fields and methods. This is used to
+/// check overrides between classes and superclasses, interfaces, and mixin
+/// applications.
+class _OverrideChecker {
+  bool _failure = false;
+  final TypeRules _rules;
+  final AnalysisErrorListener _reporter;
+
+  _OverrideChecker(this._rules, this._reporter);
+
+  void check(ClassDeclaration node) {
+    if (node.element.type.isObject) return;
+    _checkSuperOverrides(node);
+    _checkMixinApplicationOverrides(node);
+    _checkAllInterfaceOverrides(node);
+  }
+
+  /// Check overrides from mixin applications themselves. For example, in:
+  ///
+  ///      A extends B with E, F
+  ///
+  ///  we check:
+  ///
+  ///      B & E against B (equivalently how E overrides B)
+  ///      B & E & F against B & E (equivalently how F overrides both B and E)
+  void _checkMixinApplicationOverrides(ClassDeclaration node) {
+    var type = node.element.type;
+    var parent = type.superclass;
+    var mixins = type.mixins;
+
+    // Check overrides from applying mixins
+    for (int i = 0; i < mixins.length; i++) {
+      var seen = new Set<String>();
+      var current = mixins[i];
+      var errorLocation = node.withClause.mixinTypes[i];
+      for (int j = i - 1; j >= 0; j--) {
+        _checkIndividualOverridesFromType(
+            current, mixins[j], errorLocation, seen);
+      }
+      _checkIndividualOverridesFromType(current, parent, errorLocation, seen);
+    }
+  }
+
+  /// Check overrides between a class and its superclasses and mixins. For
+  /// example, in:
+  ///
+  ///      A extends B with E, F
+  ///
+  /// we check A against B, B super classes, E, and F.
+  ///
+  /// Internally we avoid reporting errors twice and we visit classes bottom up
+  /// to ensure we report the most immediate invalid override first. For
+  /// example, in the following code we'll report that `Test` has an invalid
+  /// override with respect to `Parent` (as opposed to an invalid override with
+  /// respect to `Grandparent`):
+  ///
+  ///     class Grandparent {
+  ///         m(A a) {}
+  ///     }
+  ///     class Parent extends Grandparent {
+  ///         m(A a) {}
+  ///     }
+  ///     class Test extends Parent {
+  ///         m(B a) {} // invalid override
+  ///     }
+  void _checkSuperOverrides(ClassDeclaration node) {
+    var seen = new Set<String>();
+    var current = node.element.type;
+    var visited = new Set<InterfaceType>();
+    do {
+      visited.add(current);
+      current.mixins.reversed
+          .forEach((m) => _checkIndividualOverridesFromClass(node, m, seen));
+      _checkIndividualOverridesFromClass(node, current.superclass, seen);
+      current = current.superclass;
+    } while (!current.isObject && !visited.contains(current));
+  }
+
+  /// Checks that implementations correctly override all reachable interfaces.
+  /// In particular, we need to check these overrides for the definitions in
+  /// the class itself and each its superclasses. If a superclass is not
+  /// abstract, then we can skip its transitive interfaces. For example, in:
+  ///
+  ///     B extends C implements G
+  ///     A extends B with E, F implements H, I
+  ///
+  /// we check:
+  ///
+  ///     C against G, H, and I
+  ///     B against G, H, and I
+  ///     E against H and I // no check against G because B is a concrete class
+  ///     F against H and I
+  ///     A against H and I
+  void _checkAllInterfaceOverrides(ClassDeclaration node) {
+    var seen = new Set<String>();
+    // Helper function to collect all reachable interfaces.
+    find(InterfaceType interfaceType, Set result) {
+      if (interfaceType == null || interfaceType.isObject) return;
+      if (result.contains(interfaceType)) return;
+      result.add(interfaceType);
+      find(interfaceType.superclass, result);
+      interfaceType.mixins.forEach((i) => find(i, result));
+      interfaceType.interfaces.forEach((i) => find(i, result));
+    }
+
+    // Check all interfaces reachable from the `implements` clause in the
+    // current class against definitions here and in superclasses.
+    var localInterfaces = new Set<InterfaceType>();
+    var type = node.element.type;
+    type.interfaces.forEach((i) => find(i, localInterfaces));
+    _checkInterfacesOverrides(node, localInterfaces, seen,
+        includeParents: true);
+
+    // Check also how we override locally the interfaces from parent classes if
+    // the parent class is abstract. Otherwise, these will be checked as
+    // overrides on the concrete superclass.
+    var superInterfaces = new Set<InterfaceType>();
+    var parent = type.superclass;
+    // TODO(sigmund): we don't seem to be reporting the analyzer error that a
+    // non-abstract class is not implementing an interface. See
+    // https://github.com/dart-lang/dart-dev-compiler/issues/25
+    while (parent != null && parent.element.isAbstract) {
+      parent.interfaces.forEach((i) => find(i, superInterfaces));
+      parent = parent.superclass;
+    }
+    _checkInterfacesOverrides(node, superInterfaces, seen,
+        includeParents: false);
+  }
+
+  /// Checks that [cls] and its super classes (including mixins) correctly
+  /// overrides each interface in [interfaces]. If [includeParents] is false,
+  /// then mixins are still checked, but the base type and it's transitive
+  /// supertypes are not.
+  ///
+  /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For
+  /// [ClassDeclaration]s errors are reported on the member that contains the
+  /// invalid override, for [InterfaceType]s we use [errorLocation] instead.
+  void _checkInterfacesOverrides(
+      cls, Iterable<InterfaceType> interfaces, Set<String> seen,
+      {Set<InterfaceType> visited,
+      bool includeParents: true,
+      AstNode errorLocation}) {
+    var node = cls is ClassDeclaration ? cls : null;
+    var type = cls is InterfaceType ? cls : node.element.type;
+
+    if (visited == null) {
+      visited = new Set<InterfaceType>();
+    } else if (visited.contains(type)) {
+      // Malformed type.
+      return;
+    } else {
+      visited.add(type);
+    }
+
+    // Check direct overrides on [type]
+    for (var interfaceType in interfaces) {
+      if (node != null) {
+        _checkIndividualOverridesFromClass(node, interfaceType, seen);
+      } else {
+        _checkIndividualOverridesFromType(
+            type, interfaceType, errorLocation, seen);
+      }
+    }
+
+    // Check overrides from its mixins
+    for (int i = 0; i < type.mixins.length; i++) {
+      var loc =
+          errorLocation != null ? errorLocation : node.withClause.mixinTypes[i];
+      for (var interfaceType in interfaces) {
+        // We copy [seen] so we can report separately if more than one mixin or
+        // the base class have an invalid override.
+        _checkIndividualOverridesFromType(
+            type.mixins[i], interfaceType, loc, new Set.from(seen));
+      }
+    }
+
+    // Check overrides from its superclasses
+    if (includeParents) {
+      var parent = type.superclass;
+      if (parent.isObject) return;
+      var loc = errorLocation != null ? errorLocation : node.extendsClause;
+      // No need to copy [seen] here because we made copies above when reporting
+      // errors on mixins.
+      _checkInterfacesOverrides(parent, interfaces, seen,
+          visited: visited, includeParents: true, errorLocation: loc);
+    }
+  }
+
+  /// Check that individual methods and fields in [subType] correctly override
+  /// the declarations in [baseType].
+  ///
+  /// The [errorLocation] node indicates where errors are reported, see
+  /// [_checkSingleOverride] for more details.
+  ///
+  /// The set [seen] is used to avoid reporting overrides more than once. It
+  /// is used when invoking this function multiple times when checking several
+  /// types in a class hierarchy. Errors are reported only the first time an
+  /// invalid override involving a specific member is encountered.
+  _checkIndividualOverridesFromType(InterfaceType subType,
+      InterfaceType baseType, AstNode errorLocation, Set<String> seen) {
+    void checkHelper(ExecutableElement e) {
+      if (e.isStatic) return;
+      if (seen.contains(e.name)) return;
+      if (_checkSingleOverride(e, baseType, null, errorLocation)) {
+        seen.add(e.name);
+      }
+    }
+    subType.methods.forEach(checkHelper);
+    subType.accessors.forEach(checkHelper);
+  }
+
+  /// Check that individual methods and fields in [subType] correctly override
+  /// the declarations in [baseType].
+  ///
+  /// The [errorLocation] node indicates where errors are reported, see
+  /// [_checkSingleOverride] for more details.
+  _checkIndividualOverridesFromClass(
+      ClassDeclaration node, InterfaceType baseType, Set<String> seen) {
+    for (var member in node.members) {
+      if (member is ConstructorDeclaration) continue;
+      if (member is FieldDeclaration) {
+        if (member.isStatic) continue;
+        for (var variable in member.fields.variables) {
+          var element = variable.element as PropertyInducingElement;
+          var name = element.name;
+          if (seen.contains(name)) continue;
+          var getter = element.getter;
+          var setter = element.setter;
+          bool found = _checkSingleOverride(getter, baseType, variable, member);
+          if (!variable.isFinal &&
+              !variable.isConst &&
+              _checkSingleOverride(setter, baseType, variable, member)) {
+            found = true;
+          }
+          if (found) seen.add(name);
+        }
+      } else {
+        if ((member as MethodDeclaration).isStatic) continue;
+        var method = (member as MethodDeclaration).element;
+        if (seen.contains(method.name)) continue;
+        if (_checkSingleOverride(method, baseType, member, member)) {
+          seen.add(method.name);
+        }
+      }
+    }
+  }
+
+  /// Checks that [element] correctly overrides its corresponding member in
+  /// [type]. Returns `true` if an override was found, that is, if [element] has
+  /// a corresponding member in [type] that it overrides.
+  ///
+  /// The [errorLocation] is a node where the error is reported. For example, a
+  /// bad override of a method in a class with respect to its superclass is
+  /// reported directly at the method declaration. However, invalid overrides
+  /// from base classes to interfaces, mixins to the base they are applied to,
+  /// or mixins to interfaces are reported at the class declaration, since the
+  /// base class or members on their own were not incorrect, only combining them
+  /// with the interface was problematic. For example, these are example error
+  /// locations in these cases:
+  ///
+  ///     error: base class introduces an invalid override. The type of B.foo is
+  ///     not a subtype of E.foo:
+  ///       class A extends B implements E { ... }
+  ///               ^^^^^^^^^
+  ///
+  ///     error: mixin introduces an invalid override. The type of C.foo is not
+  ///     a subtype of E.foo:
+  ///       class A extends B with C implements E { ... }
+  ///                              ^
+  ///
+  /// When checking for overrides from a type and it's super types, [node] is
+  /// the AST node that defines [element]. This is used to determine whether the
+  /// type of the element could be inferred from the types in the super classes.
+  bool _checkSingleOverride(ExecutableElement element, InterfaceType type,
+      AstNode node, AstNode errorLocation) {
+    assert(!element.isStatic);
+
+    FunctionType subType = _rules.elementType(element);
+    // TODO(vsm): Test for generic
+    FunctionType baseType = _getMemberType(type, element);
+
+    if (baseType == null) return false;
+    if (!_rules.isAssignable(subType, baseType)) {
+      // See whether non-assignable cases fit one of our common patterns:
+      //
+      // Common pattern 1: Inferable return type (on getters and methods)
+      //   class A {
+      //     int get foo => ...;
+      //     String toString() { ... }
+      //   }
+      //   class B extends A {
+      //     get foo => e; // no type specified.
+      //     toString() { ... } // no return type specified.
+      //   }
+      _recordMessage(new InvalidMethodOverride(
+          errorLocation, element, type, subType, baseType));
+    }
+    return true;
+  }
+
+  void _recordMessage(StaticInfo info) {
+    if (info == null) return;
+    var error = info.toAnalysisError();
+    if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
+    _reporter.onError(error);
+  }
+}
+
+/// Checks the body of functions and properties.
+class CodeChecker extends RecursiveAstVisitor {
+  final TypeRules rules;
+  final AnalysisErrorListener reporter;
+  final _OverrideChecker _overrideChecker;
+  final bool _hints;
+
+  bool _failure = false;
+  bool get failure => _failure || _overrideChecker._failure;
+
+  void reset() {
+    _failure = false;
+    _overrideChecker._failure = false;
+  }
+
+  CodeChecker(TypeRules rules, AnalysisErrorListener reporter,
+      {bool hints: false})
+      : rules = rules,
+        reporter = reporter,
+        _hints = hints,
+        _overrideChecker = new _OverrideChecker(rules, reporter);
+
+  @override
+  void visitComment(Comment node) {
+    // skip, no need to do typechecking inside comments (they may contain
+    // comment references which would require resolution).
+  }
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    _overrideChecker.check(node);
+    super.visitClassDeclaration(node);
+  }
+
+  @override
+  void visitAssignmentExpression(AssignmentExpression node) {
+    var token = node.operator;
+    if (token.type != TokenType.EQ) {
+      _checkCompoundAssignment(node);
+    } else {
+      DartType staticType = _getStaticType(node.leftHandSide);
+      checkAssignment(node.rightHandSide, staticType);
+    }
+    node.visitChildren(this);
+  }
+
+  /// Check constructor declaration to ensure correct super call placement.
+  @override
+  void visitConstructorDeclaration(ConstructorDeclaration node) {
+    node.visitChildren(this);
+
+    final init = node.initializers;
+    for (int i = 0, last = init.length - 1; i < last; i++) {
+      final node = init[i];
+      if (node is SuperConstructorInvocation) {
+        _recordMessage(new InvalidSuperInvocation(node));
+      }
+    }
+  }
+
+  @override
+  void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    var field = node.fieldName;
+    var element = field.staticElement;
+    DartType staticType = rules.elementType(element);
+    checkAssignment(node.expression, staticType);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitForEachStatement(ForEachStatement node) {
+    // Check that the expression is an Iterable.
+    var expr = node.iterable;
+    var iterableType = node.awaitKeyword != null
+        ? rules.provider.streamType
+        : rules.provider.iterableType;
+    var loopVariable = node.identifier != null
+        ? node.identifier
+        : node.loopVariable?.identifier;
+    if (loopVariable != null) {
+      var iteratorType = loopVariable.staticType;
+      var checkedType = iterableType.substitute4([iteratorType]);
+      checkAssignment(expr, checkedType);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitForStatement(ForStatement node) {
+    if (node.condition != null) {
+      checkBoolean(node.condition);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitIfStatement(IfStatement node) {
+    checkBoolean(node.condition);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitDoStatement(DoStatement node) {
+    checkBoolean(node.condition);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitWhileStatement(WhileStatement node) {
+    checkBoolean(node.condition);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitSwitchStatement(SwitchStatement node) {
+    // SwitchStatement defines a boolean conversion to check the result of the
+    // case value == the switch value, but in dev_compiler we require a boolean
+    // return type from an overridden == operator (because Object.==), so
+    // checking in SwitchStatement shouldn't be necessary.
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitListLiteral(ListLiteral node) {
+    var type = rules.provider.dynamicType;
+    if (node.typeArguments != null) {
+      var targs = node.typeArguments.arguments;
+      if (targs.length > 0) type = targs[0].type;
+    }
+    var elements = node.elements;
+    for (int i = 0; i < elements.length; i++) {
+      checkArgument(elements[i], type);
+    }
+    super.visitListLiteral(node);
+  }
+
+  @override
+  void visitMapLiteral(MapLiteral node) {
+    var ktype = rules.provider.dynamicType;
+    var vtype = rules.provider.dynamicType;
+    if (node.typeArguments != null) {
+      var targs = node.typeArguments.arguments;
+      if (targs.length > 0) ktype = targs[0].type;
+      if (targs.length > 1) vtype = targs[1].type;
+    }
+    var entries = node.entries;
+    for (int i = 0; i < entries.length; i++) {
+      var entry = entries[i];
+      checkArgument(entry.key, ktype);
+      checkArgument(entry.value, vtype);
+    }
+    super.visitMapLiteral(node);
+  }
+
+  // Check invocations
+  void checkArgumentList(ArgumentList node, FunctionType type) {
+    NodeList<Expression> list = node.arguments;
+    int len = list.length;
+    for (int i = 0; i < len; ++i) {
+      Expression arg = list[i];
+      ParameterElement element = arg.staticParameterElement;
+      if (element == null) {
+        if (type.parameters.length < len) {
+          // We found an argument mismatch, the analyzer will report this too,
+          // so no need to insert an error for this here.
+          continue;
+        }
+        element = type.parameters[i];
+        // TODO(vsm): When can this happen?
+        assert(element != null);
+      }
+      DartType expectedType = rules.elementType(element);
+      if (expectedType == null) expectedType = rules.provider.dynamicType;
+      checkArgument(arg, expectedType);
+    }
+  }
+
+  void checkArgument(Expression arg, DartType expectedType) {
+    // Preserve named argument structure, so their immediate parent is the
+    // method invocation.
+    if (arg is NamedExpression) {
+      arg = (arg as NamedExpression).expression;
+    }
+    checkAssignment(arg, expectedType);
+  }
+
+  void checkFunctionApplication(
+      Expression node, Expression f, ArgumentList list) {
+    if (rules.isDynamicCall(f)) {
+      // If f is Function and this is a method invocation, we should have
+      // gotten an analyzer error, so no need to issue another error.
+      _recordDynamicInvoke(node, f);
+    } else {
+      checkArgumentList(list, rules.getTypeAsCaller(f));
+    }
+  }
+
+  @override
+  visitMethodInvocation(MethodInvocation node) {
+    var target = node.realTarget;
+    if (rules.isDynamicTarget(target) &&
+        !_isObjectMethod(node, node.methodName)) {
+      _recordDynamicInvoke(node, target);
+
+      // Mark the tear-off as being dynamic, too. This lets us distinguish
+      // cases like:
+      //
+      //     dynamic d;
+      //     d.someMethod(...); // the whole method call must be a dynamic send.
+      //
+      // ... from case like:
+      //
+      //     SomeType s;
+      //     s.someDynamicField(...); // static get, followed by dynamic call.
+      //
+      // The first case is handled here, the second case is handled below when
+      // we call [checkFunctionApplication].
+      DynamicInvoke.set(node.methodName, true);
+    } else {
+      checkFunctionApplication(node, node.methodName, node.argumentList);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    checkFunctionApplication(node, node.function, node.argumentList);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitRedirectingConstructorInvocation(
+      RedirectingConstructorInvocation node) {
+    var type = node.staticElement.type;
+    checkArgumentList(node.argumentList, type);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    var element = node.staticElement;
+    if (element != null) {
+      var type = node.staticElement.type;
+      checkArgumentList(node.argumentList, type);
+    }
+    node.visitChildren(this);
+  }
+
+  void _checkReturnOrYield(Expression expression, AstNode node,
+      {bool yieldStar: false}) {
+    var body = node.getAncestor((n) => n is FunctionBody);
+    var type = rules.getExpectedReturnType(body, yieldStar: yieldStar);
+    if (type == null) {
+      // We have a type mismatch: the async/async*/sync* modifier does
+      // not match the return or yield type.  We should have already gotten an
+      // analyzer error in this case.
+      return;
+    }
+    // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
+    if (expression != null) checkAssignment(expression, type);
+  }
+
+  @override
+  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    _checkReturnOrYield(node.expression, node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitReturnStatement(ReturnStatement node) {
+    _checkReturnOrYield(node.expression, node);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitYieldStatement(YieldStatement node) {
+    _checkReturnOrYield(node.expression, node, yieldStar: node.star != null);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitPropertyAccess(PropertyAccess node) {
+    var target = node.realTarget;
+    if (rules.isDynamicTarget(target) &&
+        !_isObjectProperty(target, node.propertyName)) {
+      _recordDynamicInvoke(node, target);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitPrefixedIdentifier(PrefixedIdentifier node) {
+    final target = node.prefix;
+    if (rules.isDynamicTarget(target) &&
+        !_isObjectProperty(target, node.identifier)) {
+      _recordDynamicInvoke(node, target);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitDefaultFormalParameter(DefaultFormalParameter node) {
+    // Check that defaults have the proper subtype.
+    var parameter = node.parameter;
+    var parameterType = rules.elementType(parameter.element);
+    assert(parameterType != null);
+    var defaultValue = node.defaultValue;
+    if (defaultValue != null) {
+      checkAssignment(defaultValue, parameterType);
+    }
+
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitFieldFormalParameter(FieldFormalParameter node) {
+    var element = node.element;
+    var typeName = node.type;
+    if (typeName != null) {
+      var type = rules.elementType(element);
+      var fieldElement =
+          node.identifier.staticElement as FieldFormalParameterElement;
+      var fieldType = rules.elementType(fieldElement.field);
+      if (!rules.isSubTypeOf(type, fieldType)) {
+        var staticInfo =
+            new InvalidParameterDeclaration(rules, node, fieldType);
+        _recordMessage(staticInfo);
+      }
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitInstanceCreationExpression(InstanceCreationExpression node) {
+    var arguments = node.argumentList;
+    var element = node.staticElement;
+    if (element != null) {
+      var type = rules.elementType(node.staticElement);
+      checkArgumentList(arguments, type);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitVariableDeclarationList(VariableDeclarationList node) {
+    TypeName type = node.type;
+    if (type == null) {
+      // No checks are needed when the type is var. Although internally the
+      // typing rules may have inferred a more precise type for the variable
+      // based on the initializer.
+    } else {
+      var dartType = getType(type);
+      for (VariableDeclaration variable in node.variables) {
+        var initializer = variable.initializer;
+        if (initializer != null) {
+          checkAssignment(initializer, dartType);
+        }
+      }
+    }
+    node.visitChildren(this);
+  }
+
+  void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
+    var type = getType(typeName);
+    if (!rules.isGroundType(type)) {
+      _recordMessage(new NonGroundTypeCheckInfo(node, type));
+    }
+  }
+
+  @override
+  void visitAsExpression(AsExpression node) {
+    // We could do the same check as the IsExpression below, but that is
+    // potentially too conservative.  Instead, at runtime, we must fail hard
+    // if the Dart as and the DDC as would return different values.
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitIsExpression(IsExpression node) {
+    _checkRuntimeTypeCheck(node, node.type);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitPrefixExpression(PrefixExpression node) {
+    if (node.operator.type == TokenType.BANG) {
+      checkBoolean(node.operand);
+    } else {
+      _checkUnary(node);
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitPostfixExpression(PostfixExpression node) {
+    _checkUnary(node);
+    node.visitChildren(this);
+  }
+
+  void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) {
+    var op = node.operator;
+    if (op.isUserDefinableOperator ||
+        op.type == TokenType.PLUS_PLUS ||
+        op.type == TokenType.MINUS_MINUS) {
+      if (rules.isDynamicTarget(node.operand)) {
+        _recordDynamicInvoke(node, node.operand);
+      }
+      // For ++ and --, even if it is not dynamic, we still need to check
+      // that the user defined method accepts an `int` as the RHS.
+      // We assume Analyzer has done this already.
+    }
+  }
+
+  @override
+  void visitBinaryExpression(BinaryExpression node) {
+    var op = node.operator;
+    if (op.isUserDefinableOperator) {
+      if (rules.isDynamicTarget(node.leftOperand)) {
+        // Dynamic invocation
+        // TODO(vsm): Move this logic to the resolver?
+        if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
+          _recordDynamicInvoke(node, node.leftOperand);
+        }
+      } else {
+        var element = node.staticElement;
+        // Method invocation.
+        if (element is MethodElement) {
+          var type = element.type;
+          // Analyzer should enforce number of parameter types, but check in
+          // case we have erroneous input.
+          if (type.normalParameterTypes.isNotEmpty) {
+            checkArgument(node.rightOperand, type.normalParameterTypes[0]);
+          }
+        } else {
+          // TODO(vsm): Assert that the analyzer found an error here?
+        }
+      }
+    } else {
+      // Non-method operator.
+      switch (op.type) {
+        case TokenType.AMPERSAND_AMPERSAND:
+        case TokenType.BAR_BAR:
+          checkBoolean(node.leftOperand);
+          checkBoolean(node.rightOperand);
+          break;
+        case TokenType.BANG_EQ:
+          break;
+        case TokenType.QUESTION_QUESTION:
+          break;
+        default:
+          assert(false);
+      }
+    }
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitConditionalExpression(ConditionalExpression node) {
+    checkBoolean(node.condition);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitIndexExpression(IndexExpression node) {
+    var target = node.realTarget;
+    if (rules.isDynamicTarget(target)) {
+      _recordDynamicInvoke(node, target);
+    } else {
+      var element = node.staticElement;
+      if (element is MethodElement) {
+        var type = element.type;
+        // Analyzer should enforce number of parameter types, but check in
+        // case we have erroneous input.
+        if (type.normalParameterTypes.isNotEmpty) {
+          checkArgument(node.index, type.normalParameterTypes[0]);
+        }
+      } else {
+        // TODO(vsm): Assert that the analyzer found an error here?
+      }
+    }
+    node.visitChildren(this);
+  }
+
+  DartType getType(TypeName name) {
+    return (name == null) ? rules.provider.dynamicType : name.type;
+  }
+
+  /// Analyzer checks boolean conversions, but we need to check too, because
+  /// it uses the default assignability rules that allow `dynamic` and `Object`
+  /// to be assigned to bool with no message.
+  void checkBoolean(Expression expr) =>
+      checkAssignment(expr, rules.provider.boolType);
+
+  void checkAssignment(Expression expr, DartType type) {
+    if (expr is ParenthesizedExpression) {
+      checkAssignment(expr.expression, type);
+    } else {
+      _recordMessage(rules.checkAssignment(expr, type));
+    }
+  }
+
+  DartType _specializedBinaryReturnType(
+      TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
+    // This special cases binary return types as per 16.26 and 16.27 of the
+    // Dart language spec.
+    switch (op) {
+      case TokenType.PLUS:
+      case TokenType.MINUS:
+      case TokenType.STAR:
+      case TokenType.TILDE_SLASH:
+      case TokenType.PERCENT:
+      case TokenType.PLUS_EQ:
+      case TokenType.MINUS_EQ:
+      case TokenType.STAR_EQ:
+      case TokenType.TILDE_SLASH_EQ:
+      case TokenType.PERCENT_EQ:
+        if (t1 == rules.provider.intType &&
+            t2 == rules.provider.intType) return t1;
+        if (t1 == rules.provider.doubleType &&
+            t2 == rules.provider.doubleType) return t1;
+        // This particular combo is not spelled out in the spec, but all
+        // implementations and analyzer seem to follow this.
+        if (t1 == rules.provider.doubleType &&
+            t2 == rules.provider.intType) return t1;
+    }
+    return normalReturnType;
+  }
+
+  void _checkCompoundAssignment(AssignmentExpression expr) {
+    var op = expr.operator.type;
+    assert(op.isAssignmentOperator && op != TokenType.EQ);
+    var methodElement = expr.staticElement;
+    if (methodElement == null) {
+      // Dynamic invocation
+      _recordDynamicInvoke(expr, expr.leftHandSide);
+    } else {
+      // Sanity check the operator
+      assert(methodElement.isOperator);
+      var functionType = methodElement.type;
+      var paramTypes = functionType.normalParameterTypes;
+      assert(paramTypes.length == 1);
+      assert(functionType.namedParameterTypes.isEmpty);
+      assert(functionType.optionalParameterTypes.isEmpty);
+
+      // Check the lhs type
+      var staticInfo;
+      var rhsType = _getStaticType(expr.rightHandSide);
+      var lhsType = _getStaticType(expr.leftHandSide);
+      var returnType = _specializedBinaryReturnType(
+          op, lhsType, rhsType, functionType.returnType);
+
+      if (!rules.isSubTypeOf(returnType, lhsType)) {
+        final numType = rules.provider.numType;
+        // Try to fix up the numerical case if possible.
+        if (rules.isSubTypeOf(lhsType, numType) &&
+            rules.isSubTypeOf(lhsType, rhsType)) {
+          // This is also slightly different from spec, but allows us to keep
+          // compound operators in the int += num and num += dynamic cases.
+          staticInfo = DownCast.create(
+              rules, expr.rightHandSide, Coercion.cast(rhsType, lhsType));
+          rhsType = lhsType;
+        } else {
+          // Static type error
+          staticInfo = new StaticTypeError(rules, expr, lhsType);
+        }
+        _recordMessage(staticInfo);
+      }
+
+      // Check the rhs type
+      if (staticInfo is! CoercionInfo) {
+        var paramType = paramTypes.first;
+        staticInfo = rules.checkAssignment(expr.rightHandSide, paramType);
+        _recordMessage(staticInfo);
+      }
+    }
+  }
+
+  bool _isObjectGetter(Expression target, SimpleIdentifier id) {
+    PropertyAccessorElement element =
+        rules.provider.objectType.element.getGetter(id.name);
+    return (element != null && !element.isStatic);
+  }
+
+  bool _isObjectMethod(Expression target, SimpleIdentifier id) {
+    MethodElement element =
+        rules.provider.objectType.element.getMethod(id.name);
+    return (element != null && !element.isStatic);
+  }
+
+  bool _isObjectProperty(Expression target, SimpleIdentifier id) {
+    return _isObjectGetter(target, id) || _isObjectMethod(target, id);
+  }
+
+  DartType _getStaticType(Expression expr) {
+    return expr.staticType ?? rules.provider.dynamicType;
+  }
+
+  void _recordDynamicInvoke(AstNode node, AstNode target) {
+    if (_hints) {
+      reporter.onError(new DynamicInvoke(rules, node).toAnalysisError());
+    }
+    // TODO(jmesserly): we may eventually want to record if the whole operation
+    // (node) was dynamic, rather than the target, but this is an easier fit
+    // with what we used to do.
+    DynamicInvoke.set(target, true);
+  }
+
+  void _recordMessage(StaticInfo info) {
+    if (info == null) return;
+    var error = info.toAnalysisError();
+
+    var severity = error.errorCode.errorSeverity;
+    if (severity == ErrorSeverity.ERROR) _failure = true;
+    if (severity != ErrorSeverity.INFO || _hints) {
+      reporter.onError(error);
+    }
+
+    if (info is CoercionInfo) {
+      // TODO(jmesserly): if we're run again on the same AST, we'll produce the
+      // same annotations. This should be harmless. This might go away once
+      // CodeChecker is integrated better with analyzer, as it will know that
+      // checking has already been performed.
+      // assert(CoercionInfo.get(info.node) == null);
+      CoercionInfo.set(info.node, info);
+    }
+  }
+}
+
+/// Looks up the declaration that matches [member] in [type] and returns it's
+/// declared type.
+FunctionType _getMemberType(InterfaceType type, ExecutableElement member) =>
+    _memberTypeGetter(member)(type);
+
+typedef FunctionType _MemberTypeGetter(InterfaceType type);
+
+_MemberTypeGetter _memberTypeGetter(ExecutableElement member) {
+  String memberName = member.name;
+  final isGetter = member is PropertyAccessorElement && member.isGetter;
+  final isSetter = member is PropertyAccessorElement && member.isSetter;
+
+  FunctionType f(InterfaceType type) {
+    ExecutableElement baseMethod;
+    try {
+      if (isGetter) {
+        assert(!isSetter);
+        // Look for getter or field.
+        baseMethod = type.getGetter(memberName);
+      } else if (isSetter) {
+        baseMethod = type.getSetter(memberName);
+      } else {
+        baseMethod = type.getMethod(memberName);
+      }
+    } catch (e) {
+      // TODO(sigmund): remove this try-catch block (see issue #48).
+    }
+    if (baseMethod == null || baseMethod.isStatic) return null;
+    return baseMethod.type;
+  }
+  ;
+  return f;
+}
diff --git a/packages/analyzer/lib/src/task/strong/info.dart b/packages/analyzer/lib/src/task/strong/info.dart
new file mode 100644
index 0000000..a18f76f
--- /dev/null
+++ b/packages/analyzer/lib/src/task/strong/info.dart
@@ -0,0 +1,472 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Defines static information collected by the type checker and used later by
+/// emitters to generate code.
+// TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
+// refactored to fit into analyzer.
+library analyzer.src.task.strong.info;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+
+import 'rules.dart';
+
+// The abstract type of coercions mapping one type to another.
+// This class also exposes static builder functions which
+// check for errors and reduce redundant coercions to the identity.
+abstract class Coercion {
+  final DartType fromType;
+  final DartType toType;
+  Coercion(this.fromType, this.toType);
+  static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
+  static Coercion identity(DartType type) => new Identity(type);
+  static Coercion error() => new CoercionError();
+}
+
+// Coercion which casts one type to another
+class Cast extends Coercion {
+  Cast(DartType fromType, DartType toType) : super(fromType, toType);
+}
+
+// The identity coercion
+class Identity extends Coercion {
+  Identity(DartType fromType) : super(fromType, fromType);
+}
+
+// The error coercion.  This coercion signals that a coercion
+// could not be generated.  The code generator should not see
+// these.
+class CoercionError extends Coercion {
+  CoercionError() : super(null, null);
+}
+
+// TODO(jmesserly): this could use some refactoring. These are essentially
+// like ErrorCodes in analyzer, but we're including some details in our message.
+// Analyzer instead has template strings, and replaces '{0}' with the first
+// argument.
+abstract class StaticInfo {
+  /// AST Node this info is attached to.
+  AstNode get node;
+
+  // TODO(jmesserly): review the usage of error codes. We probably want our own,
+  // as well as some DDC specific [ErrorType]s.
+  ErrorCode toErrorCode();
+
+  // TODO(jmesserly): what convention to use here?
+  String get name => 'dev_compiler.$runtimeType';
+
+  List<Object> get arguments => [node];
+
+  AnalysisError toAnalysisError() {
+    int begin = node is AnnotatedNode
+        ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
+        : node.offset;
+    int length = node.end - begin;
+    var source = (node.root as CompilationUnit).element.source;
+    return new AnalysisError(source, begin, length, toErrorCode(), arguments);
+  }
+}
+
+/// Implicitly injected expression conversion.
+abstract class CoercionInfo extends StaticInfo {
+  final TypeRules rules;
+
+  final Expression node;
+
+  DartType get convertedType;
+
+  CoercionInfo(this.rules, this.node);
+
+  DartType get baseType => rules.getStaticType(node);
+  DartType get staticType => convertedType;
+
+  String get message;
+  toErrorCode() => new HintCode(name, message);
+
+  static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+
+  /// Gets the coercion info associated with this node.
+  static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
+
+  /// Sets the coercion info associated with this node.
+  static CoercionInfo set(AstNode node, CoercionInfo info) {
+    node.setProperty(_propertyName, info);
+    return info;
+  }
+}
+
+// Base class for all casts from base type to sub type.
+abstract class DownCast extends CoercionInfo {
+  Cast _cast;
+
+  DownCast._internal(TypeRules rules, Expression expression, this._cast)
+      : super(rules, expression) {
+    assert(_cast.toType != baseType &&
+        _cast.fromType == baseType &&
+        (baseType.isDynamic ||
+            // Call methods make the following non-redundant
+            _cast.toType.isSubtypeOf(baseType) ||
+            baseType.isAssignableTo(_cast.toType)));
+  }
+
+  Cast get cast => _cast;
+
+  DartType get convertedType => _cast.toType;
+
+  @override List<Object> get arguments => [node, baseType, convertedType];
+  @override String get message => '{0} ({1}) will need runtime check '
+      'to cast to type {2}';
+
+  // Factory to create correct DownCast variant.
+  static StaticInfo create(TypeRules rules, Expression expression, Cast cast,
+      {String reason}) {
+    final fromT = cast.fromType;
+    final toT = cast.toType;
+
+    // toT <:_R fromT => to <: fromT
+    // NB: classes with call methods are subtypes of function
+    // types, but the function type is not assignable to the class
+    assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
+
+    // Handle null call specially.
+    if (expression is NullLiteral) {
+      // TODO(vsm): Create a NullCast for this once we revisit nonnullability.
+      return new DownCastImplicit(rules, expression, cast);
+    }
+
+    // Inference "casts":
+    if (expression is Literal) {
+      // fromT should be an exact type - this will almost certainly fail at
+      // runtime.
+      return new StaticTypeError(rules, expression, toT, reason: reason);
+    }
+    if (expression is FunctionExpression) {
+      // fromT should be an exact type - this will almost certainly fail at
+      // runtime.
+      return new UninferredClosure(rules, expression, cast);
+    }
+    if (expression is InstanceCreationExpression) {
+      // fromT should be an exact type - this will almost certainly fail at
+      // runtime.
+      return new StaticTypeError(rules, expression, toT, reason: reason);
+    }
+
+    // Composite cast: these are more likely to fail.
+    if (!rules.isGroundType(toT)) {
+      // This cast is (probably) due to our different treatment of dynamic.
+      // It may be more likely to fail at runtime.
+      return new DownCastComposite(rules, expression, cast);
+    }
+
+    // Dynamic cast
+    if (fromT.isDynamic) {
+      return new DynamicCast(rules, expression, cast);
+    }
+
+    // Assignment cast
+    var parent = expression.parent;
+    if (parent is VariableDeclaration && (parent.initializer == expression)) {
+      return new AssignmentCast(rules, expression, cast);
+    }
+
+    // Other casts
+    return new DownCastImplicit(rules, expression, cast);
+  }
+}
+
+//
+// Standard down casts.  These casts are implicitly injected by the compiler.
+//
+
+// A down cast from dynamic to T.
+class DynamicCast extends DownCast {
+  DynamicCast(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+// A down cast due to a variable declaration to a ground type.  E.g.,
+//   T x = expr;
+// where T is ground.  We exclude non-ground types as these behave differently
+// compared to standard Dart.
+class AssignmentCast extends DownCast {
+  AssignmentCast(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+//
+// Temporary "casts" of allocation sites - literals, constructor invocations,
+// and closures.  These should be handled by contextual inference.  In most
+// cases, inference will be sufficient, though in some it may unmask an actual
+// error: e.g.,
+//   List<int> l = [1, 2, 3]; // Inference succeeds
+//   List<String> l = [1, 2, 3]; // Inference reveals static type error
+// We're marking all as warnings for now.
+//
+// TODO(vsm,leafp): Remove this.
+class UninferredClosure extends DownCast {
+  UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  toErrorCode() => new StaticTypeWarningCode(name, message);
+}
+
+//
+// Implicit down casts.  These are only injected by the compiler by flag.
+//
+
+// A down cast to a non-ground type.  These behave differently from standard
+// Dart and may be more likely to fail at runtime.
+class DownCastComposite extends DownCast {
+  DownCastComposite(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  toErrorCode() => new StaticTypeWarningCode(name, message);
+}
+
+// A down cast to a non-ground type.  These behave differently from standard
+// Dart and may be more likely to fail at runtime.
+class DownCastImplicit extends DownCast {
+  DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
+      : super._internal(rules, expression, cast);
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+// An inferred type for the wrapped expression, which may need to be
+// reified into the term
+abstract class InferredTypeBase extends CoercionInfo {
+  final DartType _type;
+
+  InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
+      : super(rules, expression);
+
+  DartType get type => _type;
+  DartType get convertedType => type;
+  @override String get message => '{0} has inferred type {1}';
+  @override List get arguments => [node, type];
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+// Standard / unspecialized inferred type
+class InferredType extends InferredTypeBase {
+  InferredType(TypeRules rules, Expression expression, DartType type)
+      : super._internal(rules, expression, type);
+
+  // Factory to create correct InferredType variant.
+  static InferredTypeBase create(
+      TypeRules rules, Expression expression, DartType type) {
+    // Specialized inference:
+    if (expression is Literal) {
+      return new InferredTypeLiteral(rules, expression, type);
+    }
+    if (expression is InstanceCreationExpression) {
+      return new InferredTypeAllocation(rules, expression, type);
+    }
+    if (expression is FunctionExpression) {
+      return new InferredTypeClosure(rules, expression, type);
+    }
+    return new InferredType(rules, expression, type);
+  }
+}
+
+// An infered type for a literal expression.
+class InferredTypeLiteral extends InferredTypeBase {
+  InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
+      : super._internal(rules, expression, type);
+}
+
+// An inferred type for a non-literal allocation site.
+class InferredTypeAllocation extends InferredTypeBase {
+  InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
+      : super._internal(rules, expression, type);
+}
+
+// An inferred type for a closure expression
+class InferredTypeClosure extends InferredTypeBase {
+  InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
+      : super._internal(rules, expression, type);
+}
+
+class DynamicInvoke extends CoercionInfo {
+  DynamicInvoke(TypeRules rules, Expression expression)
+      : super(rules, expression);
+
+  DartType get convertedType => rules.provider.dynamicType;
+  String get message => '{0} requires dynamic invoke';
+  toErrorCode() => new HintCode(name, message);
+
+  static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
+
+  /// Whether this [node] is the target of a dynamic operation.
+  static bool get(AstNode node) {
+    var value = node.getProperty(_propertyName);
+    return value != null ? value : false;
+  }
+
+  /// Sets whether this node is the target of a dynamic operation.
+  static bool set(AstNode node, bool value) {
+    // Free the storage for things that aren't dynamic.
+    if (value == false) value = null;
+    node.setProperty(_propertyName, value);
+    return value;
+  }
+}
+
+abstract class StaticError extends StaticInfo {
+  final AstNode node;
+
+  StaticError(this.node);
+
+  String get message;
+
+  toErrorCode() => new CompileTimeErrorCode(name, message);
+}
+
+class StaticTypeError extends StaticError {
+  final DartType baseType;
+  final DartType expectedType;
+  String reason = null;
+
+  StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
+      {this.reason})
+      : baseType = rules.getStaticType(expression),
+        super(expression);
+
+  @override List<Object> get arguments => [node, baseType, expectedType];
+  @override String get message =>
+      'Type check failed: {0} ({1}) is not of type {2}' +
+          ((reason == null) ? '' : ' because $reason');
+}
+
+class InvalidVariableDeclaration extends StaticError {
+  final DartType expectedType;
+
+  InvalidVariableDeclaration(
+      TypeRules rules, AstNode declaration, this.expectedType)
+      : super(declaration);
+
+  @override List<Object> get arguments => [expectedType];
+  @override String get message => 'Type check failed: null is not of type {0}';
+}
+
+class InvalidParameterDeclaration extends StaticError {
+  final DartType expectedType;
+
+  InvalidParameterDeclaration(
+      TypeRules rules, FormalParameter declaration, this.expectedType)
+      : super(declaration);
+
+  @override List<Object> get arguments => [node, expectedType];
+  @override String get message => 'Type check failed: {0} is not of type {1}';
+}
+
+class NonGroundTypeCheckInfo extends StaticInfo {
+  final DartType type;
+  final AstNode node;
+
+  NonGroundTypeCheckInfo(this.node, this.type) {
+    assert(node is IsExpression || node is AsExpression);
+  }
+
+  @override List<Object> get arguments => [type];
+  String get message =>
+      "Runtime check on non-ground type {0} may throw StrongModeError";
+
+  toErrorCode() => new HintCode(name, message);
+}
+
+// Invalid override of an instance member of a class.
+abstract class InvalidOverride extends StaticError {
+  /// Member declaration with the invalid override.
+  final ExecutableElement element;
+
+  /// Type (class or interface) that provides the base declaration.
+  final InterfaceType base;
+
+  /// Actual type of the overridden member.
+  final DartType subType;
+
+  /// Actual type of the base member.
+  final DartType baseType;
+
+  /// Whether the error comes from combining a base class and an interface
+  final bool fromBaseClass;
+
+  /// Whether the error comes from a mixin (either overriding a base class or an
+  /// interface declaration).
+  final bool fromMixin;
+
+  InvalidOverride(
+      AstNode node, this.element, this.base, this.subType, this.baseType)
+      : fromBaseClass = node is ExtendsClause,
+        fromMixin = node.parent is WithClause,
+        super(node);
+
+  ClassElement get parent => element.enclosingElement;
+
+  @override List<Object> get arguments =>
+      [parent.name, element.name, subType, base, baseType];
+
+  String _messageHelper(String errorName) {
+    var lcErrorName = errorName.toLowerCase();
+    var intro = fromBaseClass
+        ? 'Base class introduces an $lcErrorName'
+        : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName);
+    return '$intro. The type of {0}.{1} ({2}) is not a '
+        'subtype of {3}.{1} ({4}).';
+  }
+}
+
+// Invalid override due to incompatible type.  I.e., the overridden signature
+// is not compatible with the original.
+class InvalidMethodOverride extends InvalidOverride {
+  InvalidMethodOverride(AstNode node, ExecutableElement element,
+      InterfaceType base, FunctionType subType, FunctionType baseType)
+      : super(node, element, base, subType, baseType);
+
+  String get message => _messageHelper('Invalid override');
+}
+
+/// Dart constructors have one weird quirk, illustrated with this example:
+///
+///     class Base {
+///       var x;
+///       Base() : x = print('Base.1') {
+///         print('Base.2');
+///       }
+///     }
+///
+///     class Derived extends Base {
+///       var y, z;
+///       Derived()
+///           : y = print('Derived.1'),
+///             super(),
+///             z = print('Derived.2') {
+///         print('Derived.3');
+///       }
+///     }
+///
+/// The order will be Derived.1, Base.1, Derived.2, Base.2, Derived.3; this
+/// ordering preserves the invariant that code can't observe uninitialized
+/// state, however it results in super constructor body not being run
+/// immediately after super initializers. Normally this isn't observable, but it
+/// could be if initializers have side effects.
+///
+/// Better to have `super` at the end, as required by the Dart style guide:
+/// <http://goo.gl/q1T4BB>
+///
+/// For now this is the only pattern we support.
+class InvalidSuperInvocation extends StaticError {
+  InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
+
+  @override String get message => "super call must be last in an initializer "
+      "list (see http://goo.gl/q1T4BB): {0}";
+}
diff --git a/packages/analyzer/lib/src/task/strong/rules.dart b/packages/analyzer/lib/src/task/strong/rules.dart
new file mode 100644
index 0000000..b575dbf
--- /dev/null
+++ b/packages/analyzer/lib/src/task/strong/rules.dart
@@ -0,0 +1,770 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
+// refactored to fit into analyzer.
+library analyzer.src.task.strong.rules;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+import 'info.dart';
+
+// TODO(jmesserly): this entire file needs to be removed in favor of TypeSystem.
+
+final _objectMap = new Expando('providerToObjectMap');
+Map<String, DartType> getObjectMemberMap(TypeProvider typeProvider) {
+  var map = _objectMap[typeProvider] as Map<String, DartType>;
+  if (map == null) {
+    map = <String, DartType>{};
+    _objectMap[typeProvider] = map;
+    var objectType = typeProvider.objectType;
+    var element = objectType.element;
+    // Only record methods (including getters) with no parameters.  As parameters are contravariant wrt
+    // type, using Object's version may be too strict.
+    // Add instance methods.
+    element.methods.where((method) => !method.isStatic).forEach((method) {
+      map[method.name] = method.type;
+    });
+    // Add getters.
+    element.accessors
+        .where((member) => !member.isStatic && member.isGetter)
+        .forEach((member) {
+      map[member.name] = member.type.returnType;
+    });
+  }
+  return map;
+}
+
+class TypeRules {
+  final TypeProvider provider;
+
+  /// Map of fields / properties / methods on Object.
+  final Map<String, DartType> objectMembers;
+
+  DownwardsInference inferrer;
+
+  TypeRules(TypeProvider provider)
+      : provider = provider,
+        objectMembers = getObjectMemberMap(provider) {
+    inferrer = new DownwardsInference(this);
+  }
+
+  /// Given a type t, if t is an interface type with a call method
+  /// defined, return the function type for the call method, otherwise
+  /// return null.
+  FunctionType getCallMethodType(DartType t) {
+    if (t is InterfaceType) {
+      ClassElement element = t.element;
+      InheritanceManager manager = new InheritanceManager(element.library);
+      FunctionType callType = manager.lookupMemberType(t, "call");
+      return callType;
+    }
+    return null;
+  }
+
+  /// Given an expression, return its type assuming it is
+  /// in the caller position of a call (that is, accounting
+  /// for the possibility of a call method).  Returns null
+  /// if expression is not statically callable.
+  FunctionType getTypeAsCaller(Expression applicand) {
+    var t = getStaticType(applicand);
+    if (t is InterfaceType) {
+      return getCallMethodType(t);
+    }
+    if (t is FunctionType) return t;
+    return null;
+  }
+
+  /// Gets the expected return type of the given function [body], either from
+  /// a normal return/yield, or from a yield*.
+  DartType getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
+    FunctionType functionType;
+    var parent = body.parent;
+    if (parent is Declaration) {
+      functionType = elementType(parent.element);
+    } else {
+      assert(parent is FunctionExpression);
+      functionType = getStaticType(parent);
+    }
+
+    var type = functionType.returnType;
+
+    InterfaceType expectedType = null;
+    if (body.isAsynchronous) {
+      if (body.isGenerator) {
+        // Stream<T> -> T
+        expectedType = provider.streamType;
+      } else {
+        // Future<T> -> T
+        // TODO(vsm): Revisit with issue #228.
+        expectedType = provider.futureType;
+      }
+    } else {
+      if (body.isGenerator) {
+        // Iterable<T> -> T
+        expectedType = provider.iterableType;
+      } else {
+        // T -> T
+        return type;
+      }
+    }
+    if (yieldStar) {
+      if (type.isDynamic) {
+        // Ensure it's at least a Stream / Iterable.
+        return expectedType.substitute4([provider.dynamicType]);
+      } else {
+        // Analyzer will provide a separate error if expected type
+        // is not compatible with type.
+        return type;
+      }
+    }
+    if (type.isDynamic) {
+      return type;
+    } else if (type is InterfaceType && type.element == expectedType.element) {
+      return type.typeArguments[0];
+    } else {
+      // Malformed type - fallback on analyzer error.
+      return null;
+    }
+  }
+
+  DartType getStaticType(Expression expr) {
+    return expr.staticType ?? provider.dynamicType;
+  }
+
+  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
+    if (t.isDynamic && dynamicIsBottom) return true;
+    // TODO(vsm): We need direct support for non-nullability in DartType.
+    // This should check on "true/nonnullable" Bottom
+    if (t.isBottom) return true;
+    return false;
+  }
+
+  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
+    if (t.isDynamic && !dynamicIsBottom) return true;
+    if (t.isObject) return true;
+    return false;
+  }
+
+  bool _anyParameterType(FunctionType ft, bool predicate(DartType t)) {
+    return ft.normalParameterTypes.any(predicate) ||
+        ft.optionalParameterTypes.any(predicate) ||
+        ft.namedParameterTypes.values.any(predicate);
+  }
+
+  // TODO(leafp): Revisit this.
+  bool isGroundType(DartType t) {
+    if (t is TypeParameterType) return false;
+    if (_isTop(t)) return true;
+
+    if (t is FunctionType) {
+      if (!_isTop(t.returnType) ||
+          _anyParameterType(t, (pt) => !_isBottom(pt, dynamicIsBottom: true))) {
+        return false;
+      } else {
+        return true;
+      }
+    }
+
+    if (t is InterfaceType) {
+      var typeArguments = t.typeArguments;
+      for (var typeArgument in typeArguments) {
+        if (!_isTop(typeArgument)) return false;
+      }
+      return true;
+    }
+
+    // We should not see any other type aside from malformed code.
+    return false;
+  }
+
+  /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC
+  /// checker to determine whether f1 would be a subtype of f2 if the return
+  /// type of f1 is set to match f2's return type.
+  // [fuzzyArrows] indicates whether or not the f1 and f2 should be
+  // treated as fuzzy arrow types (and hence dynamic parameters to f2 treated as
+  // bottom).
+  bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2,
+      {bool fuzzyArrows: true, bool ignoreReturn: false}) {
+    final r1s = f1.normalParameterTypes;
+    final o1s = f1.optionalParameterTypes;
+    final n1s = f1.namedParameterTypes;
+    final r2s = f2.normalParameterTypes;
+    final o2s = f2.optionalParameterTypes;
+    final n2s = f2.namedParameterTypes;
+    final ret1 = ignoreReturn ? f2.returnType : f1.returnType;
+    final ret2 = f2.returnType;
+
+    // A -> B <: C -> D if C <: A and
+    // either D is void or B <: D
+    if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false;
+
+    // Reject if one has named and the other has optional
+    if (n1s.length > 0 && o2s.length > 0) return false;
+    if (n2s.length > 0 && o1s.length > 0) return false;
+
+    // f2 has named parameters
+    if (n2s.length > 0) {
+      // Check that every named parameter in f2 has a match in f1
+      for (String k2 in n2s.keys) {
+        if (!n1s.containsKey(k2)) return false;
+        if (!isSubTypeOf(n2s[k2], n1s[k2],
+            dynamicIsBottom: fuzzyArrows)) return false;
+      }
+    }
+    // If we get here, we either have no named parameters,
+    // or else the named parameters match and we have no optional
+    // parameters
+
+    // If f1 has more required parameters, reject
+    if (r1s.length > r2s.length) return false;
+
+    // If f2 has more required + optional parameters, reject
+    if (r2s.length + o2s.length > r1s.length + o1s.length) return false;
+
+    // The parameter lists must look like the following at this point
+    // where rrr is a region of required, and ooo is a region of optionals.
+    // f1: rrr ooo ooo ooo
+    // f2: rrr rrr ooo
+    int rr = r1s.length; // required in both
+    int or = r2s.length - r1s.length; // optional in f1, required in f2
+    int oo = o2s.length; // optional in both
+
+    for (int i = 0; i < rr; ++i) {
+      if (!isSubTypeOf(r2s[i], r1s[i],
+          dynamicIsBottom: fuzzyArrows)) return false;
+    }
+    for (int i = 0, j = rr; i < or; ++i, ++j) {
+      if (!isSubTypeOf(r2s[j], o1s[i],
+          dynamicIsBottom: fuzzyArrows)) return false;
+    }
+    for (int i = or, j = 0; i < oo; ++i, ++j) {
+      if (!isSubTypeOf(o2s[j], o1s[i],
+          dynamicIsBottom: fuzzyArrows)) return false;
+    }
+    return true;
+  }
+
+  bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) {
+    if (i1 == i2) return true;
+
+    if (i1.element == i2.element) {
+      List<DartType> tArgs1 = i1.typeArguments;
+      List<DartType> tArgs2 = i2.typeArguments;
+
+      // TODO(leafp): Verify that this is always true
+      // Do raw types get filled in?
+      assert(tArgs1.length == tArgs2.length);
+
+      for (int i = 0; i < tArgs1.length; i++) {
+        DartType t1 = tArgs1[i];
+        DartType t2 = tArgs2[i];
+        if (!isSubTypeOf(t1, t2)) return false;
+      }
+      return true;
+    }
+
+    if (i2.isDartCoreFunction) {
+      if (i1.element.getMethod("call") != null) return true;
+    }
+
+    if (i1 == provider.objectType) return false;
+
+    if (_isInterfaceSubTypeOf(i1.superclass, i2)) return true;
+
+    for (final parent in i1.interfaces) {
+      if (_isInterfaceSubTypeOf(parent, i2)) return true;
+    }
+
+    for (final parent in i1.mixins) {
+      if (_isInterfaceSubTypeOf(parent, i2)) return true;
+    }
+
+    return false;
+  }
+
+  bool isSubTypeOf(DartType t1, DartType t2, {bool dynamicIsBottom: false}) {
+    if (t1 == t2) return true;
+
+    // Trivially true.
+    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
+      return true;
+    }
+
+    // Trivially false.
+    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
+      return false;
+    }
+
+    // The null type is a subtype of any nullable type, which is all Dart types.
+    // TODO(vsm): Note, t1.isBottom still allows for null confusingly.
+    // _isBottom(t1) does not necessarily imply t1.isBottom if there are
+    // nonnullable types in the system.
+    if (t1.isBottom) {
+      return true;
+    }
+
+    // S <: T where S is a type variable
+    //  T is not dynamic or object (handled above)
+    //  S != T (handled above)
+    //  So only true if bound of S is S' and
+    //  S' <: T
+    if (t1 is TypeParameterType) {
+      DartType bound = t1.element.bound;
+      if (bound == null) return false;
+      return isSubTypeOf(bound, t2);
+    }
+
+    if (t2 is TypeParameterType) {
+      return false;
+    }
+
+    if (t2.isDartCoreFunction) {
+      if (t1 is FunctionType) return true;
+      if (t1.element is ClassElement) {
+        if ((t1.element as ClassElement).getMethod("call") != null) return true;
+      }
+    }
+
+    // "Traditional" name-based subtype check.
+    if (t1 is InterfaceType && t2 is InterfaceType) {
+      return _isInterfaceSubTypeOf(t1, t2);
+    }
+
+    if (t1 is! FunctionType && t2 is! FunctionType) return false;
+
+    if (t1 is InterfaceType && t2 is FunctionType) {
+      var callType = getCallMethodType(t1);
+      if (callType == null) return false;
+      return isFunctionSubTypeOf(callType, t2);
+    }
+
+    if (t1 is FunctionType && t2 is InterfaceType) {
+      return false;
+    }
+
+    // Functions
+    // Note: it appears under the hood all Dart functions map to a class /
+    // hidden type that:
+    //  (a) subtypes Object (an internal _FunctionImpl in the VM)
+    //  (b) implements Function
+    //  (c) provides standard Object members (hashCode, toString)
+    //  (d) contains private members (corresponding to _FunctionImpl?)
+    //  (e) provides a call method to handle the actual function invocation
+    //
+    // The standard Dart subtyping rules are structural in nature.  I.e.,
+    // bivariant on arguments and return type.
+    //
+    // The below tries for a more traditional subtyping rule:
+    // - covariant on return type
+    // - contravariant on parameters
+    // - 'sensible' (?) rules on optional and/or named params
+    // but doesn't properly mix with class subtyping.  I suspect Java 8 lambdas
+    // essentially map to dynamic (and rely on invokedynamic) due to similar
+    // issues.
+    return isFunctionSubTypeOf(t1 as FunctionType, t2 as FunctionType);
+  }
+
+  bool isAssignable(DartType t1, DartType t2) {
+    return isSubTypeOf(t1, t2);
+  }
+
+  // Produce a coercion which coerces something of type fromT
+  // to something of type toT.
+  // If wrap is true and both are function types, a closure
+  // wrapper coercion is produced using _wrapTo (see above)
+  // Returns the error coercion if the types cannot be coerced
+  // according to our current criteria.
+  Coercion _coerceTo(DartType fromT, DartType toT) {
+    // We can use anything as void
+    if (toT.isVoid) return Coercion.identity(toT);
+
+    // fromT <: toT, no coercion needed
+    if (isSubTypeOf(fromT, toT)) return Coercion.identity(toT);
+
+    // For now, reject conversions between function types and
+    // call method objects.  We could choose to allow casts here.
+    // Wrapping a function type to assign it to a call method
+    // object will never succeed.  Wrapping the other way could
+    // be allowed.
+    if ((fromT is FunctionType && getCallMethodType(toT) != null) ||
+        (toT is FunctionType && getCallMethodType(fromT) != null)) {
+      return Coercion.error();
+    }
+
+    // Downcast if toT <: fromT
+    if (isSubTypeOf(toT, fromT)) return Coercion.cast(fromT, toT);
+
+    // Downcast if toT <===> fromT
+    // The intention here is to allow casts that are sideways in the restricted
+    // type system, but allowed in the regular dart type system, since these
+    // are likely to succeed.  The canonical example is List<dynamic> and
+    // Iterable<T> for some concrete T (e.g. Object).  These are unrelated
+    // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
+    if (fromT.isAssignableTo(toT)) {
+      return Coercion.cast(fromT, toT);
+    }
+    return Coercion.error();
+  }
+
+  StaticInfo checkAssignment(Expression expr, DartType toT) {
+    final fromT = getStaticType(expr);
+    final Coercion c = _coerceTo(fromT, toT);
+    if (c is Identity) return null;
+    if (c is CoercionError) return new StaticTypeError(this, expr, toT);
+    var reason = null;
+
+    var errors = <String>[];
+    var ok = inferrer.inferExpression(expr, toT, errors);
+    if (ok) return InferredType.create(this, expr, toT);
+    reason = (errors.isNotEmpty) ? errors.first : null;
+
+    if (c is Cast) return DownCast.create(this, expr, c, reason: reason);
+    assert(false);
+    return null;
+  }
+
+  DartType elementType(Element e) {
+    if (e == null) {
+      // Malformed code - just return dynamic.
+      return provider.dynamicType;
+    }
+    return (e as dynamic).type;
+  }
+
+  bool _isLibraryPrefix(Expression node) =>
+      node is SimpleIdentifier && node.staticElement is PrefixElement;
+
+  /// Returns `true` if the target expression is dynamic.
+  bool isDynamicTarget(Expression node) {
+    if (node == null) return false;
+
+    if (_isLibraryPrefix(node)) return false;
+
+    // Null type happens when we have unknown identifiers, like a dart: import
+    // that doesn't resolve.
+    var type = node.staticType;
+    return type == null || type.isDynamic;
+  }
+
+  /// Returns `true` if the expression is a dynamic function call or method
+  /// invocation.
+  bool isDynamicCall(Expression call) {
+    var ft = getTypeAsCaller(call);
+    // TODO(leafp): This will currently return true if t is Function
+    // This is probably the most correct thing to do for now, since
+    // this code is also used by the back end.  Maybe revisit at some
+    // point?
+    if (ft == null) return true;
+    // Dynamic as the parameter type is treated as bottom.  A function with
+    // a dynamic parameter type requires a dynamic call in general.
+    // However, as an optimization, if we have an original definition, we know
+    // dynamic is reified as Object - in this case a regular call is fine.
+    if (call is SimpleIdentifier) {
+      var element = call.staticElement;
+      if (element is FunctionElement || element is MethodElement) {
+        // An original declaration.
+        return false;
+      }
+    }
+
+    return _anyParameterType(ft, (pt) => pt.isDynamic);
+  }
+}
+
+class DownwardsInference {
+  final TypeRules rules;
+
+  DownwardsInference(this.rules);
+
+  /// Called for each list literal which gets inferred
+  void annotateListLiteral(ListLiteral e, List<DartType> targs) {}
+
+  /// Called for each map literal which gets inferred
+  void annotateMapLiteral(MapLiteral e, List<DartType> targs) {}
+
+  /// Called for each new/const which gets inferred
+  void annotateInstanceCreationExpression(
+      InstanceCreationExpression e, List<DartType> targs) {}
+
+  /// Called for cast from dynamic required for inference to succeed
+  void annotateCastFromDynamic(Expression e, DartType t) {}
+
+  /// Called for each function expression return type inferred
+  void annotateFunctionExpression(FunctionExpression e, DartType returnType) {}
+
+  /// Downward inference
+  bool inferExpression(Expression e, DartType t, List<String> errors) {
+    // Don't cast top level expressions, only sub-expressions
+    return _inferExpression(e, t, errors, cast: false);
+  }
+
+  /// Downward inference
+  bool _inferExpression(Expression e, DartType t, List<String> errors,
+      {cast: true}) {
+    if (e is ConditionalExpression) {
+      return _inferConditionalExpression(e, t, errors);
+    }
+    if (e is ParenthesizedExpression) {
+      return _inferParenthesizedExpression(e, t, errors);
+    }
+    if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true;
+    if (cast && rules.getStaticType(e).isDynamic) {
+      annotateCastFromDynamic(e, t);
+      return true;
+    }
+    if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors);
+    if (e is ListLiteral) return _inferListLiteral(e, t, errors);
+    if (e is MapLiteral) return _inferMapLiteral(e, t, errors);
+    if (e is NamedExpression) return _inferNamedExpression(e, t, errors);
+    if (e is InstanceCreationExpression) {
+      return _inferInstanceCreationExpression(e, t, errors);
+    }
+    errors.add("$e cannot be typed as $t");
+    return false;
+  }
+
+  /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype
+  /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'>
+  /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm'
+  /// to derive a concrete instantation for I of the form <T0, ..., Tn>,
+  /// such that I<T0, .., Tn> <: t2
+  List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
+    if (t1 == t2) return t2.typeArguments;
+    var tArgs1 = t1.typeArguments;
+    var tArgs2 = t2.typeArguments;
+    // If t1 isn't a raw type, bail out
+    if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) return null;
+
+    // This is our inferred type argument list.  We start at all dynamic,
+    // and fill in with inferred types when we reach a match.
+    var actuals =
+        new List<DartType>.filled(tArgs1.length, rules.provider.dynamicType);
+
+    // When we find the supertype of t1 with the same
+    // classname as t2 (see below), we have the following:
+    // If t1 is an instantiation of a class T1<X0, ..., Xn>
+    // and t2 is an instantiation of a class T2<Y0, ...., Ym>
+    // of the form t2 = T2<S0, ..., Sm>
+    // then we want to choose instantiations for the Xi
+    // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
+    // To find this, we simply instantate T1 with
+    // X0, ..., Xn, and then find its superclass
+    // T2<T0', ..., Tn'>.  We then solve the constraint
+    // set T0' <: S0, ..., Tn' <: Sn for the Xi.
+    // Currently, we only handle constraints where
+    // the Ti' is one of the Xi'.  If there are multiple
+    // constraints on some Xi, we choose the lower of the
+    // two (if it exists).
+    bool permute(List<DartType> permutedArgs) {
+      if (permutedArgs == null) return false;
+      var ps = t1.typeParameters;
+      var ts = ps.map((p) => p.type).toList();
+      for (int i = 0; i < permutedArgs.length; i++) {
+        var tVar = permutedArgs[i];
+        var tActual = tArgs2[i];
+        var index = ts.indexOf(tVar);
+        if (index >= 0 && rules.isSubTypeOf(tActual, actuals[index])) {
+          actuals[index] = tActual;
+        }
+      }
+      return actuals.any((x) => !x.isDynamic);
+    }
+
+    // Look for the first supertype of t1 with the same class name as t2.
+    bool match(InterfaceType t1) {
+      if (t1.element == t2.element) {
+        return permute(t1.typeArguments);
+      }
+
+      if (t1 == rules.provider.objectType) return false;
+
+      if (match(t1.superclass)) return true;
+
+      for (final parent in t1.interfaces) {
+        if (match(parent)) return true;
+      }
+
+      for (final parent in t1.mixins) {
+        if (match(parent)) return true;
+      }
+      return false;
+    }
+
+    // We have that t1 = T1<dynamic, ..., dynamic>.
+    // To match t1 against t2, we use the uninstantiated version
+    // of t1, essentially treating it as an instantiation with
+    // fresh variables, and solve for the variables.
+    // t1.element.type will be of the form T1<X0, ..., Xn>
+    if (!match(t1.element.type)) return null;
+    var newT1 = t1.element.type.substitute4(actuals);
+    // If we found a solution, return it.
+    if (rules.isSubTypeOf(newT1, t2)) return actuals;
+    return null;
+  }
+
+  /// These assume that e is not already a subtype of t
+
+  bool _inferConditionalExpression(
+      ConditionalExpression e, DartType t, errors) {
+    return _inferExpression(e.thenExpression, t, errors) &&
+        _inferExpression(e.elseExpression, t, errors);
+  }
+
+  bool _inferParenthesizedExpression(
+      ParenthesizedExpression e, DartType t, errors) {
+    return _inferExpression(e.expression, t, errors);
+  }
+
+  bool _inferInstanceCreationExpression(
+      InstanceCreationExpression e, DartType t, errors) {
+    var arguments = e.argumentList.arguments;
+    var rawType = rules.getStaticType(e);
+    // rawType is the instantiated type of the instance
+    if (rawType is! InterfaceType) return false;
+    var type = (rawType as InterfaceType);
+    if (type.typeParameters == null ||
+        type.typeParameters.length == 0) return false;
+    if (e.constructorName.type == null) return false;
+    // classTypeName is the type name of the class being instantiated
+    var classTypeName = e.constructorName.type;
+    // Check that we were not passed any type arguments
+    if (classTypeName.typeArguments != null) return false;
+    // Infer type arguments
+    if (t is! InterfaceType) return false;
+    var targs = _matchTypes(type, t);
+    if (targs == null) return false;
+    if (e.staticElement == null) return false;
+    var constructorElement = e.staticElement;
+    // From the constructor element get:
+    //  the instantiated type of the constructor, then
+    //     the uninstantiated element for the constructor, then
+    //        the uninstantiated type for the constructor
+    var rawConstructorElement =
+        constructorElement.type.element as ConstructorElement;
+    var baseType = rawConstructorElement.type;
+    if (baseType == null) return false;
+    // From the interface type (instantiated), get:
+    //  the uninstantiated element, then
+    //    the uninstantiated type, then
+    //      the type arguments (aka the type parameters)
+    var tparams = type.element.type.typeArguments;
+    // Take the uninstantiated constructor type, and replace the type
+    // parameters with the inferred arguments.
+    var fType = baseType.substitute2(targs, tparams);
+    {
+      var rTypes = fType.normalParameterTypes;
+      var oTypes = fType.optionalParameterTypes;
+      var pTypes = new List.from(rTypes)..addAll(oTypes);
+      var pArgs = arguments.where((x) => x is! NamedExpression);
+      var pi = 0;
+      for (var arg in pArgs) {
+        if (pi >= pTypes.length) return false;
+        var argType = pTypes[pi];
+        if (!_inferExpression(arg, argType, errors)) return false;
+        pi++;
+      }
+      var nTypes = fType.namedParameterTypes;
+      for (var arg0 in arguments) {
+        if (arg0 is! NamedExpression) continue;
+        var arg = arg0 as NamedExpression;
+        SimpleIdentifier nameNode = arg.name.label;
+        String name = nameNode.name;
+        var argType = nTypes[name];
+        if (argType == null) return false;
+        if (!_inferExpression(arg, argType, errors)) return false;
+      }
+    }
+    annotateInstanceCreationExpression(e, targs);
+    return true;
+  }
+
+  bool _inferNamedExpression(NamedExpression e, DartType t, errors) {
+    return _inferExpression(e.expression, t, errors);
+  }
+
+  bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) {
+    if (t is! FunctionType) return false;
+    var fType = t as FunctionType;
+    var eType = e.staticType as FunctionType;
+    if (eType is! FunctionType) return false;
+
+    // We have a function literal, so we can treat the arrow type
+    // as non-fuzzy.  Since we're not improving on parameter types
+    // currently, if this check fails then we cannot succeed, so
+    // bail out.  Otherwise, we never need to check the parameter types
+    // again.
+    if (!rules.isFunctionSubTypeOf(eType, fType,
+        fuzzyArrows: false, ignoreReturn: true)) return false;
+
+    // This only entered inference because of fuzzy typing.
+    // The function type is already specific enough, we can just
+    // succeed and treat it as a successful inference
+    if (rules.isSubTypeOf(eType.returnType, fType.returnType)) return true;
+
+    // Fuzzy typing again, handle the void case (not caught by the previous)
+    if (fType.returnType.isVoid) return true;
+
+    if (e.body is! ExpressionFunctionBody) return false;
+    var body = (e.body as ExpressionFunctionBody).expression;
+    if (!_inferExpression(body, fType.returnType, errors)) return false;
+
+    // TODO(leafp): Try narrowing the argument types if possible
+    // to get better code in the function body.  This requires checking
+    // that the body is well-typed at the more specific type.
+
+    // At this point, we know that the parameter types are in the appropriate subtype
+    // relation, and we have checked that we can type the body at the appropriate return
+    // type, so we can are done.
+    annotateFunctionExpression(e, fType.returnType);
+    return true;
+  }
+
+  bool _inferListLiteral(ListLiteral e, DartType t, errors) {
+    var dyn = rules.provider.dynamicType;
+    var listT = rules.provider.listType.substitute4([dyn]);
+    // List <: t (using dart rules) must be true
+    if (!listT.isSubtypeOf(t)) return false;
+    // The list literal must have no type arguments
+    if (e.typeArguments != null) return false;
+    if (t is! InterfaceType) return false;
+    var targs = _matchTypes(listT, t);
+    if (targs == null) return false;
+    assert(targs.length == 1);
+    var etype = targs[0];
+    assert(!etype.isDynamic);
+    var elements = e.elements;
+    var b = elements.every((e) => _inferExpression(e, etype, errors));
+    if (b) annotateListLiteral(e, targs);
+    return b;
+  }
+
+  bool _inferMapLiteral(MapLiteral e, DartType t, errors) {
+    var dyn = rules.provider.dynamicType;
+    var mapT = rules.provider.mapType.substitute4([dyn, dyn]);
+    // Map <: t (using dart rules) must be true
+    if (!mapT.isSubtypeOf(t)) return false;
+    // The map literal must have no type arguments
+    if (e.typeArguments != null) return false;
+    if (t is! InterfaceType) return false;
+    var targs = _matchTypes(mapT, t);
+    if (targs == null) return false;
+    assert(targs.length == 2);
+    var kType = targs[0];
+    var vType = targs[1];
+    assert(!(kType.isDynamic && vType.isDynamic));
+    var entries = e.entries;
+    bool inferEntry(MapLiteralEntry entry) {
+      return _inferExpression(entry.key, kType, errors) &&
+          _inferExpression(entry.value, vType, errors);
+    }
+    var b = entries.every(inferEntry);
+    if (b) annotateMapLiteral(e, targs);
+    return b;
+  }
+}
diff --git a/packages/analyzer/lib/task/model.dart b/packages/analyzer/lib/task/model.dart
index 9d949c3..7b70f8e 100644
--- a/packages/analyzer/lib/task/model.dart
+++ b/packages/analyzer/lib/task/model.dart
@@ -59,7 +59,7 @@
 /**
  * An object with which an analysis result can be associated.
  *
- * Clients are allowed to subtype this class when creating new kinds of targets.
+ * 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].
  */
@@ -75,7 +75,7 @@
  * An object used to compute one or more analysis results associated with a
  * single target.
  *
- * Clients are expected to extend this class when creating new tasks.
+ * Clients must extend this class when creating new tasks.
  */
 abstract class AnalysisTask {
   /**
@@ -198,7 +198,7 @@
    * map should be fully populated (have a key/value pair for each result that
    * this task is expected to produce) or the [caughtException] should be set.
    *
-   * Clients should not override this method.
+   * Clients may not override this method.
    */
   void perform() {
     try {
@@ -217,7 +217,7 @@
    * Perform this analysis task, ensuring that all exceptions are wrapped in an
    * [AnalysisException].
    *
-   * Clients should not override this method.
+   * Clients may not override this method.
    */
   void _safelyPerform() {
     try {
@@ -273,7 +273,7 @@
  * A description of a [List]-based analysis result that can be computed by an
  * [AnalysisTask].
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
   /**
@@ -293,7 +293,7 @@
  * A description of an input to an [AnalysisTask] that can be used to compute
  * that input.
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class ListTaskInput<E> extends TaskInput<List<E>> {
   /**
@@ -328,7 +328,7 @@
 /**
  * A description of an input with a [Map] based values.
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
   /**
@@ -347,6 +347,8 @@
  *
  * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
  * share the same total size in a cache.
+ *
+ * Clients may implement this class when implementing plugins.
  */
 abstract class ResultCachingPolicy<T> {
   /**
@@ -370,7 +372,7 @@
 /**
  * A description of an analysis result that can be computed by an [AnalysisTask].
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class ResultDescriptor<V> {
   /**
@@ -410,7 +412,7 @@
 /**
  * A specification of the given [result] for the given [target].
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 class TargetedResult {
   /**
@@ -451,6 +453,8 @@
 
 /**
  * A description of an [AnalysisTask].
+ *
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class TaskDescriptor {
   /**
@@ -492,7 +496,7 @@
  * A description of an input to an [AnalysisTask] that can be used to compute
  * that input.
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class TaskInput<V> {
   /**
@@ -520,7 +524,7 @@
  * indicating that there are no more requests, the method [inputValue] can be
  * used to access the value of the input that was built.
  *
- * Clients are not expected to subtype this class.
+ * Clients may not extend, implement or mix-in this class.
  */
 abstract class TaskInputBuilder<V> {
   /**
@@ -588,6 +592,8 @@
  *
  * They know specific of the targets and results they care about,
  * so they can request analysis results in optimal order.
+ *
+ * Clients may implement this class when implementing plugins.
  */
 abstract class WorkManager {
   /**
diff --git a/packages/analyzer/pubspec.yaml b/packages/analyzer/pubspec.yaml
index 3e8fa88..8ae644d 100644
--- a/packages/analyzer/pubspec.yaml
+++ b/packages/analyzer/pubspec.yaml
@@ -1,10 +1,10 @@
 name: analyzer
-version: 0.26.1+9
+version: 0.26.1+14
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
 environment:
-  sdk: '>=1.11.0 <2.0.0'
+  sdk: '>=1.12.0 <2.0.0'
 dependencies:
   args: '>=0.12.1 <0.14.0'
   glob: ^1.0.3
diff --git a/packages/analyzer/test/file_system/memory_file_system_test.dart b/packages/analyzer/test/file_system/memory_file_system_test.dart
index 3d239ae..d0d3e55 100644
--- a/packages/analyzer/test/file_system/memory_file_system_test.dart
+++ b/packages/analyzer/test/file_system/memory_file_system_test.dart
@@ -339,6 +339,13 @@
     expect(relative.path, '/foo/bar/baz.dart');
   }
 
+  void test_resolveRelative_dart() {
+    File file = provider.newFile('/sdk/lib/core/core.dart', '');
+    Source source = file.createSource(Uri.parse('dart:core'));
+    Uri resolved = source.resolveRelativeUri(Uri.parse('int.dart'));
+    expect(resolved.toString(), 'dart:core/int.dart');
+  }
+
   void test_shortName() {
     expect(source.shortName, 'test.dart');
   }
diff --git a/packages/analyzer/test/generated/all_the_rest_test.dart b/packages/analyzer/test/generated/all_the_rest_test.dart
index cabe5d7..25c3465 100644
--- a/packages/analyzer/test/generated/all_the_rest_test.dart
+++ b/packages/analyzer/test/generated/all_the_rest_test.dart
@@ -609,7 +609,7 @@
     expect(result.isValid, isTrue);
     DartObject value = result.value;
     expect(value.type.name, "double");
-    expect(value.doubleValue.isInfinite, isTrue);
+    expect(value.toDoubleValue().isInfinite, isTrue);
   }
 
   void test_divide_int_int() {
@@ -825,7 +825,7 @@
     EvaluationResult result = _getExpressionValue(contents);
     DartObject value = result.value;
     expect(value.type.name, "bool");
-    expect(value.boolValue, expectedValue);
+    expect(value.toBoolValue(), expectedValue);
   }
 
   void _assertValue2(double expectedValue, String contents) {
@@ -833,7 +833,7 @@
     expect(result.isValid, isTrue);
     DartObject value = result.value;
     expect(value.type.name, "double");
-    expect(value.doubleValue, expectedValue);
+    expect(value.toDoubleValue(), expectedValue);
   }
 
   void _assertValue3(int expectedValue, String contents) {
@@ -841,7 +841,7 @@
     expect(result.isValid, isTrue);
     DartObject value = result.value;
     expect(value.type.name, "int");
-    expect(value.intValue, expectedValue);
+    expect(value.toIntValue(), expectedValue);
   }
 
   void _assertValue4(String expectedValue, String contents) {
@@ -851,7 +851,7 @@
     ParameterizedType type = value.type;
     expect(type, isNotNull);
     expect(type.name, "String");
-    expect(value.stringValue, expectedValue);
+    expect(value.toStringValue(), expectedValue);
   }
 
   EvaluationResult _getExpressionValue(String contents) {
@@ -2165,7 +2165,7 @@
       Map<String, DartObjectImpl> fields, String fieldName, int expectedValue) {
     DartObjectImpl field = fields[fieldName];
     expect(field.type.name, "int");
-    expect(field.intValue, expectedValue);
+    expect(field.toIntValue(), expectedValue);
   }
 
   void _assertNullField(Map<String, DartObjectImpl> fields, String fieldName) {
@@ -2198,7 +2198,7 @@
     expect(result.value, isNotNull);
     DartObjectImpl value = result.value;
     expect(value.type, typeProvider.boolType);
-    bool boolValue = value.boolValue;
+    bool boolValue = value.toBoolValue();
     expect(boolValue, isNotNull);
     return boolValue;
   }
@@ -2207,7 +2207,7 @@
     expect(result.value, isNotNull);
     DartObjectImpl value = result.value;
     expect(value.type, typeProvider.intType);
-    return value.intValue;
+    return value.toIntValue();
   }
 
   void _assertValidNull(EvaluationResultImpl result) {
@@ -2527,7 +2527,7 @@
   void _assertValue(int expectedValue, DartObjectImpl result) {
     expect(result, isNotNull);
     expect(result.type.name, "int");
-    expect(result.intValue, expectedValue);
+    expect(result.toIntValue(), expectedValue);
   }
 
   NonExistingSource _dummySource() {
@@ -3140,84 +3140,84 @@
     _assertGreaterThanOrEqual(_boolValue(null), _intValue(null), _intValue(2));
   }
 
-  void test_hasExactValue_bool_false() {
-    expect(_boolValue(false).hasExactValue, isTrue);
+  void test_hasKnownValue_bool_false() {
+    expect(_boolValue(false).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_bool_true() {
-    expect(_boolValue(true).hasExactValue, isTrue);
+  void test_hasKnownValue_bool_true() {
+    expect(_boolValue(true).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_bool_unknown() {
-    expect(_boolValue(null).hasExactValue, isTrue);
+  void test_hasKnownValue_bool_unknown() {
+    expect(_boolValue(null).hasKnownValue, isFalse);
   }
 
-  void test_hasExactValue_double_known() {
-    expect(_doubleValue(2.3).hasExactValue, isTrue);
+  void test_hasKnownValue_double_known() {
+    expect(_doubleValue(2.3).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_double_unknown() {
-    expect(_doubleValue(null).hasExactValue, isTrue);
+  void test_hasKnownValue_double_unknown() {
+    expect(_doubleValue(null).hasKnownValue, isFalse);
   }
 
-  void test_hasExactValue_dynamic() {
-    expect(_dynamicValue().hasExactValue, isFalse);
+  void test_hasKnownValue_dynamic() {
+    expect(_dynamicValue().hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_int_known() {
-    expect(_intValue(23).hasExactValue, isTrue);
+  void test_hasKnownValue_int_known() {
+    expect(_intValue(23).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_int_unknown() {
-    expect(_intValue(null).hasExactValue, isTrue);
+  void test_hasKnownValue_int_unknown() {
+    expect(_intValue(null).hasKnownValue, isFalse);
   }
 
-  void test_hasExactValue_list_empty() {
-    expect(_listValue().hasExactValue, isTrue);
+  void test_hasKnownValue_list_empty() {
+    expect(_listValue().hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_list_invalid() {
-    expect(_dynamicValue().hasExactValue, isFalse);
+  void test_hasKnownValue_list_invalidElement() {
+    expect(_listValue([_dynamicValue]).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_list_valid() {
-    expect(_listValue([_intValue(23)]).hasExactValue, isTrue);
+  void test_hasKnownValue_list_valid() {
+    expect(_listValue([_intValue(23)]).hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_map_empty() {
-    expect(_mapValue().hasExactValue, isTrue);
+  void test_hasKnownValue_map_empty() {
+    expect(_mapValue().hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_map_invalidKey() {
-    expect(_mapValue([_dynamicValue(), _stringValue("value")]).hasExactValue,
-        isFalse);
-  }
-
-  void test_hasExactValue_map_invalidValue() {
-    expect(_mapValue([_stringValue("key"), _dynamicValue()]).hasExactValue,
-        isFalse);
-  }
-
-  void test_hasExactValue_map_valid() {
-    expect(
-        _mapValue([_stringValue("key"), _stringValue("value")]).hasExactValue,
+  void test_hasKnownValue_map_invalidKey() {
+    expect(_mapValue([_dynamicValue(), _stringValue("value")]).hasKnownValue,
         isTrue);
   }
 
-  void test_hasExactValue_null() {
-    expect(_nullValue().hasExactValue, isTrue);
+  void test_hasKnownValue_map_invalidValue() {
+    expect(_mapValue([_stringValue("key"), _dynamicValue()]).hasKnownValue,
+        isTrue);
   }
 
-  void test_hasExactValue_num() {
-    expect(_numValue().hasExactValue, isFalse);
+  void test_hasKnownValue_map_valid() {
+    expect(
+        _mapValue([_stringValue("key"), _stringValue("value")]).hasKnownValue,
+        isTrue);
   }
 
-  void test_hasExactValue_string_known() {
-    expect(_stringValue("twenty-three").hasExactValue, isTrue);
+  void test_hasKnownValue_null() {
+    expect(_nullValue().hasKnownValue, isTrue);
   }
 
-  void test_hasExactValue_string_unknown() {
-    expect(_stringValue(null).hasExactValue, isTrue);
+  void test_hasKnownValue_num() {
+    expect(_numValue().hasKnownValue, isFalse);
+  }
+
+  void test_hasKnownValue_string_known() {
+    expect(_stringValue("twenty-three").hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_string_unknown() {
+    expect(_stringValue(null).hasKnownValue, isFalse);
   }
 
   void test_identical_bool_false() {
@@ -4774,7 +4774,7 @@
     variables.define(variableName, "false");
     DartObject object = variables.getBool(typeProvider, variableName);
     expect(object, isNotNull);
-    expect(object.boolValue, false);
+    expect(object.toBoolValue(), false);
   }
 
   void test_getBool_invalid() {
@@ -4793,7 +4793,7 @@
     variables.define(variableName, "true");
     DartObject object = variables.getBool(typeProvider, variableName);
     expect(object, isNotNull);
-    expect(object.boolValue, true);
+    expect(object.toBoolValue(), true);
   }
 
   void test_getBool_undefined() {
@@ -4828,7 +4828,7 @@
     variables.define(variableName, "23");
     DartObject object = variables.getInt(typeProvider, variableName);
     expect(object, isNotNull);
-    expect(object.intValue, 23);
+    expect(object.toIntValue(), 23);
   }
 
   void test_getString_defined() {
@@ -4839,7 +4839,7 @@
     variables.define(variableName, value);
     DartObject object = variables.getString(typeProvider, variableName);
     expect(object, isNotNull);
-    expect(object.stringValue, value);
+    expect(object.toStringValue(), value);
   }
 
   void test_getString_undefined() {
@@ -6673,6 +6673,34 @@
     expect(variable.setter, isNull);
   }
 
+  void test_visitVariableDeclaration_top_docRange() {
+    // final a, b;
+    ElementHolder holder = new ElementHolder();
+    ElementBuilder builder = new ElementBuilder(holder);
+    VariableDeclaration variableDeclaration1 =
+        AstFactory.variableDeclaration('a');
+    VariableDeclaration variableDeclaration2 =
+        AstFactory.variableDeclaration('b');
+    TopLevelVariableDeclaration topLevelVariableDeclaration = AstFactory
+        .topLevelVariableDeclaration(
+            Keyword.FINAL, null, [variableDeclaration1, variableDeclaration2]);
+    topLevelVariableDeclaration.documentationComment = AstFactory
+        .documentationComment(
+            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+
+    topLevelVariableDeclaration.accept(builder);
+    List<TopLevelVariableElement> variables = holder.topLevelVariables;
+    expect(variables, hasLength(2));
+
+    TopLevelVariableElement variable1 = variables[0];
+    expect(variable1, isNotNull);
+    _assertHasDocRange(variable1, 50, 7);
+
+    TopLevelVariableElement variable2 = variables[1];
+    expect(variable2, isNotNull);
+    _assertHasDocRange(variable2, 50, 7);
+  }
+
   void test_visitVariableDeclaration_top_final() {
     // final v;
     ElementHolder holder = new ElementHolder();
@@ -8944,7 +8972,7 @@
 final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
   'first' : const LibraryInfo(
     'first/first.dart',
-    category: 'First',
+    categories: 'Client',
     documented: true,
     platforms: VM_PLATFORM,
     dart2jsPath: 'first/first_dart2js.dart'),
@@ -8953,7 +8981,7 @@
     expect(libraryMap.size(), 1);
     SdkLibrary first = libraryMap.getLibrary("dart:first");
     expect(first, isNotNull);
-    expect(first.category, "First");
+    expect(first.category, "Client");
     expect(first.path, "first/first_dart2js.dart");
     expect(first.shortName, "dart:first");
     expect(first.isDart2JsLibrary, false);
@@ -8976,13 +9004,13 @@
 final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
   'first' : const LibraryInfo(
     'first/first.dart',
-    category: 'First',
+    categories: 'Client',
     documented: true,
     platforms: VM_PLATFORM),
 
   'second' : const LibraryInfo(
     'second/second.dart',
-    category: 'Second',
+    categories: 'Server',
     documented: false,
     implementation: true,
     platforms: 0),
@@ -8991,7 +9019,7 @@
     expect(libraryMap.size(), 2);
     SdkLibrary first = libraryMap.getLibrary("dart:first");
     expect(first, isNotNull);
-    expect(first.category, "First");
+    expect(first.category, "Client");
     expect(first.path, "first/first.dart");
     expect(first.shortName, "dart:first");
     expect(first.isDart2JsLibrary, false);
@@ -9000,7 +9028,7 @@
     expect(first.isVmLibrary, true);
     SdkLibrary second = libraryMap.getLibrary("dart:second");
     expect(second, isNotNull);
-    expect(second.category, "Second");
+    expect(second.category, "Server");
     expect(second.path, "second/second.dart");
     expect(second.shortName, "dart:second");
     expect(second.isDart2JsLibrary, false);
diff --git a/packages/analyzer/test/generated/ast_test.dart b/packages/analyzer/test/generated/ast_test.dart
index e7c2025..e25c253 100644
--- a/packages/analyzer/test/generated/ast_test.dart
+++ b/packages/analyzer/test/generated/ast_test.dart
@@ -2318,6 +2318,13 @@
             AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0)));
   }
 
+  void test_visitDefaultFormalParameter_annotation() {
+    DefaultFormalParameter parameter = AstFactory.positionalFormalParameter(
+        AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0));
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A p = 0', parameter);
+  }
+
   void test_visitDoStatement() {
     _assertSource(
         "do {} while (c);",
@@ -2460,6 +2467,12 @@
         AstFactory.fieldFormalParameter(null, AstFactory.typeName4("A"), "a"));
   }
 
+  void test_visitFieldFormalParameter_annotation() {
+    FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('f');
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A this.f', parameter);
+  }
+
   void test_visitForEachStatement_declared() {
     _assertSource(
         "for (var a in b) {}",
@@ -2898,6 +2911,12 @@
     _assertSource("f()", AstFactory.functionTypedFormalParameter(null, "f"));
   }
 
+  void test_visitFunctionTypedFormalParameter_annotation() {
+    FunctionTypedFormalParameter parameter = AstFactory.functionTypedFormalParameter(null, "f");
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A f()', parameter);
+  }
+
   void test_visitFunctionTypedFormalParameter_type() {
     _assertSource(
         "T f()",
@@ -3521,6 +3540,12 @@
         AstFactory.simpleFormalParameter4(AstFactory.typeName4("A"), "a"));
   }
 
+  void test_visitSimpleFormalParameter_annotation() {
+    SimpleFormalParameter parameter = AstFactory.simpleFormalParameter3('x');
+    parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertSource('@A x', parameter);
+  }
+
   void test_visitSimpleIdentifier() {
     _assertSource("a", AstFactory.identifier3("a"));
   }
diff --git a/packages/analyzer/test/generated/engine_test.dart b/packages/analyzer/test/generated/engine_test.dart
index 310df94..7224060 100644
--- a/packages/analyzer/test/generated/engine_test.dart
+++ b/packages/analyzer/test/generated/engine_test.dart
@@ -31,7 +31,7 @@
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/string_source.dart';
-import 'package:analyzer/task/model.dart' hide AnalysisTask, WorkManager;
+import 'package:analyzer/task/model.dart' as newContext;
 import 'package:html/dom.dart' show Document;
 import 'package:path/path.dart' as pathos;
 import 'package:typed_mock/typed_mock.dart';
@@ -865,6 +865,15 @@
     });
   }
 
+  void test_configurationData() {
+    var key = new newContext.ResultDescriptor('test_key', '');
+    var testData = ['test', 'data'];
+    _context.setConfigurationData(key, testData);
+    expect(_context.getConfigurationData(key), testData);
+    var unusedKey = new newContext.ResultDescriptor('unused_key', '');
+    expect(_context.getConfigurationData(unusedKey), null);
+  }
+
   void test_dispose() {
     expect(_context.isDisposed, isFalse);
     _context.dispose();
@@ -5695,7 +5704,7 @@
   }
 
   @override
-  List<AnalysisTarget> get explicitTargets {
+  List<newContext.AnalysisTarget> get explicitTargets {
     fail("Unexpected invocation of visitCacheItems");
     return null;
   }
@@ -5766,7 +5775,7 @@
   }
 
   @override
-  List<AnalysisTarget> get priorityTargets {
+  List<newContext.AnalysisTarget> get priorityTargets {
     fail("Unexpected invocation of visitCacheItems");
     return null;
   }
@@ -5818,15 +5827,20 @@
   }
 
   @override
+  TypeResolverVisitorFactory get typeResolverVisitorFactory {
+    fail("Unexpected invocation of getTypeResolverVisitorFactory");
+    return null;
+  }
+
+  @override
   TypeSystem get typeSystem {
     fail("Unexpected invocation of getTypeSystem");
     return null;
   }
 
   @override
-  TypeResolverVisitorFactory get typeResolverVisitorFactory {
-    fail("Unexpected invocation of getTypeResolverVisitorFactory");
-    return null;
+  List<newContext.WorkManager> get workManagers {
+    fail("Unexpected invocation of workManagers");
   }
 
   @override
@@ -5907,7 +5921,8 @@
   }
 
   @override
-  Object computeResult(AnalysisTarget target, ResultDescriptor result) {
+  Object computeResult(
+      newContext.AnalysisTarget target, newContext.ResultDescriptor result) {
     fail("Unexpected invocation of computeResult");
     return null;
   }
@@ -5930,7 +5945,7 @@
   }
 
   @override
-  CacheEntry getCacheEntry(AnalysisTarget target) {
+  CacheEntry getCacheEntry(newContext.AnalysisTarget target) {
     fail("Unexpected invocation of visitCacheItems");
     return null;
   }
@@ -5943,6 +5958,11 @@
   }
 
   @override
+  Object getConfigurationData(newContext.ResultDescriptor key) {
+    fail("Unexpected invocation of getConfigurationData");
+  }
+
+  @override
   TimestampedData<String> getContents(Source source) {
     fail("Unexpected invocation of getContents");
     return null;
@@ -6055,7 +6075,8 @@
   }
 
   @override
-  Object getResult(AnalysisTarget target, ResultDescriptor result) {
+  Object getResult(
+      newContext.AnalysisTarget target, newContext.ResultDescriptor result) {
     fail("Unexpected invocation of getResult");
     return null;
   }
@@ -6091,7 +6112,8 @@
   }
 
   @override
-  Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) {
+  Stream<ComputedResult> onResultComputed(
+      newContext.ResultDescriptor descriptor) {
     fail("Unexpected invocation of onResultComputed");
     return null;
   }
@@ -6158,6 +6180,11 @@
   }
 
   @override
+  void setConfigurationData(newContext.ResultDescriptor key, Object data) {
+    fail("Unexpected invocation of setConfigurationData");
+  }
+
+  @override
   void setContents(Source source, String contents) {
     fail("Unexpected invocation of setContents");
   }
diff --git a/packages/analyzer/test/generated/non_error_resolver_test.dart b/packages/analyzer/test/generated/non_error_resolver_test.dart
index dedbb2a..8a6c71f 100644
--- a/packages/analyzer/test/generated/non_error_resolver_test.dart
+++ b/packages/analyzer/test/generated/non_error_resolver_test.dart
@@ -691,6 +691,32 @@
     verify([source]);
   }
 
+  void test_bug_24539_getter() {
+    Source source = addSource('''
+class C<T> {
+  List<Foo> get x => null;
+}
+
+typedef Foo(param);
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_bug_24539_setter() {
+    Source source = addSource('''
+class C<T> {
+  void set x(List<Foo> value) {}
+}
+
+typedef Foo(param);
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_builtInIdentifierAsType_dynamic() {
     Source source = addSource(r'''
 f() {
diff --git a/packages/analyzer/test/generated/parser_test.dart b/packages/analyzer/test/generated/parser_test.dart
index 98e80de..51e4941 100644
--- a/packages/analyzer/test/generated/parser_test.dart
+++ b/packages/analyzer/test/generated/parser_test.dart
@@ -3221,6 +3221,17 @@
     expect(expression.thenExpression.isSynthetic, isTrue);
   }
 
+  void test_declarationBeforeDirective() {
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+        "class foo { } import 'bar.dart';",
+        [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION]);
+    expect(unit.directives, hasLength(1));
+    expect(unit.declarations, hasLength(1));
+    ClassDeclaration classDecl = unit.childEntities.first;
+    expect(classDecl, isNotNull);
+    expect(classDecl.name.name, 'foo');
+  }
+
   void test_equalityExpression_missing_LHS() {
     BinaryExpression expression =
         parseExpression("== y", [ParserErrorCode.MISSING_IDENTIFIER]);
@@ -3338,17 +3349,6 @@
     parseExpression("m(f() => 0);", [ParserErrorCode.EXPECTED_TOKEN]);
   }
 
-  void test_declarationBeforeDirective() {
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
-        "class foo { } import 'bar.dart';",
-        [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION]);
-    expect(unit.directives, hasLength(1));
-    expect(unit.declarations, hasLength(1));
-    ClassDeclaration classDecl = unit.childEntities.first;
-    expect(classDecl, isNotNull);
-    expect(classDecl.name.name, 'foo');
-  }
-
   void test_importDirectivePartial_as() {
     CompilationUnit unit = ParserTestCase.parseCompilationUnit(
         "import 'b.dart' d as b;", [ParserErrorCode.UNEXPECTED_TOKEN]);
@@ -3549,6 +3549,53 @@
     expect(field.name.isSynthetic, isTrue);
   }
 
+  void test_incompleteForEach() {
+    ForStatement statement = ParserTestCase.parseStatement(
+        'for (String item i) {}',
+        [ParserErrorCode.EXPECTED_TOKEN, ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<ForStatement>());
+    expect(statement.toSource(), 'for (String item; i;) {}');
+    expect(statement.leftSeparator, isNotNull);
+    expect(statement.leftSeparator.type, TokenType.SEMICOLON);
+    expect(statement.rightSeparator, isNotNull);
+    expect(statement.rightSeparator.type, TokenType.SEMICOLON);
+  }
+
+  void test_incompleteLocalVariable_atTheEndOfBlock() {
+    Statement statement = ParserTestCase.parseStatement(
+        'String v }', [ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<VariableDeclarationStatement>());
+    expect(statement.toSource(), 'String v;');
+  }
+
+  void test_incompleteLocalVariable_beforeIdentifier() {
+    Statement statement = ParserTestCase.parseStatement(
+        'String v String v2;', [ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<VariableDeclarationStatement>());
+    expect(statement.toSource(), 'String v;');
+  }
+
+  void test_incompleteLocalVariable_beforeKeyword() {
+    Statement statement = ParserTestCase.parseStatement(
+        'String v if (true) {}', [ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<VariableDeclarationStatement>());
+    expect(statement.toSource(), 'String v;');
+  }
+
+  void test_incompleteLocalVariable_beforeNextBlock() {
+    Statement statement = ParserTestCase.parseStatement(
+        'String v {}', [ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<VariableDeclarationStatement>());
+    expect(statement.toSource(), 'String v;');
+  }
+
+  void test_incompleteLocalVariable_parameterizedType() {
+    Statement statement = ParserTestCase.parseStatement(
+        'List<String> v {}', [ParserErrorCode.EXPECTED_TOKEN]);
+    expect(statement, new isInstanceOf<VariableDeclarationStatement>());
+    expect(statement.toSource(), 'List<String> v;');
+  }
+
   void test_invalidFunctionBodyModifier() {
     ParserTestCase.parseCompilationUnit(
         "f() sync {}", [ParserErrorCode.MISSING_STAR_AFTER_SYNC]);
@@ -9423,7 +9470,7 @@
     expect(identifier.name, lexeme);
   }
 
-  void test_parseStatement_emptyTypeArgumentListt() {
+  void test_parseStatement_emptyTypeArgumentList() {
     VariableDeclarationStatement statement = parse4(
         "parseStatement", "C<> c;", [ParserErrorCode.EXPECTED_TYPE_NAME]);
     VariableDeclarationList variables = statement.variables;
diff --git a/packages/analyzer/test/src/context/context_test.dart b/packages/analyzer/test/src/context/context_test.dart
index 0544bf5..12f6fa7 100644
--- a/packages/analyzer/test/src/context/context_test.dart
+++ b/packages/analyzer/test/src/context/context_test.dart
@@ -649,6 +649,15 @@
     });
   }
 
+  void test_configurationData() {
+    var key = new ResultDescriptor('test_key', '');
+    var testData = ['test', 'data'];
+    context.setConfigurationData(key, testData);
+    expect(context.getConfigurationData(key), testData);
+    var unusedKey = new ResultDescriptor('unused_key', '');
+    expect(context.getConfigurationData(unusedKey), null);
+  }
+
   void test_dispose() {
     expect(context.isDisposed, isFalse);
     context.dispose();
@@ -905,7 +914,7 @@
     List<AnalysisError> errors = errorInfo.errors;
     expect(errors, hasLength(0));
     errors = context.computeErrors(source);
-    expect(errors, hasLength(3));
+    expect(errors, hasLength(2));
   }
 
   void test_getHtmlFilesReferencing_html() {
@@ -1191,6 +1200,43 @@
     fail("The added source was not in the list of library sources");
   }
 
+  void test_getLibrarySources_inSDK() {
+    Source source = addSource(
+        '/test.dart',
+        r'''
+import 'dart:async';
+Stream S = null;
+''');
+    LibraryElement testLibrary = context.computeLibraryElement(source);
+    // prepare "Stream" ClassElement
+    ClassElement streamElement;
+    {
+      CompilationUnitElement testUnit = testLibrary.definingCompilationUnit;
+      InterfaceType streamType = testUnit.topLevelVariables[0].type;
+      streamElement = streamType.element;
+    }
+    // must be from SDK context
+    AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
+    expect(sdkContext, streamElement.context);
+    Source intSource = streamElement.source;
+    // must be in the "async" library - SDK context
+    {
+      List<Source> coreLibraries = sdkContext.getLibrariesContaining(intSource);
+      expect(coreLibraries, hasLength(1));
+      Source coreSource = coreLibraries[0];
+      expect(coreSource.isInSystemLibrary, isTrue);
+      expect(coreSource.shortName, 'async.dart');
+    }
+    // must be in the "async" library - main context
+    {
+      List<Source> coreLibraries = context.getLibrariesContaining(intSource);
+      expect(coreLibraries, hasLength(1));
+      Source coreSource = coreLibraries[0];
+      expect(coreSource.isInSystemLibrary, isTrue);
+      expect(coreSource.shortName, 'async.dart');
+    }
+  }
+
   void test_getLineInfo() {
     Source source = addSource(
         "/test.dart",
@@ -1718,9 +1764,9 @@
 </script></body></html>''');
     _analyzeAll_assertFinished();
     context.computeErrors(htmlSource);
-    expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(htmlSource)),
-        isTrue,
-        reason: "htmlSource has an error");
+//    expect(_hasAnalysisErrorWithErrorSeverity(context.getErrors(htmlSource)),
+//        isTrue,
+//        reason: "htmlSource has an error");
     // add libB.dart and analyze
     Source libBSource = addSource("/libB.dart", "library libB;");
     _analyzeAll_assertFinished();
diff --git a/packages/analyzer/test/src/context/mock_sdk.dart b/packages/analyzer/test/src/context/mock_sdk.dart
index 25de8b3..121fb5d 100644
--- a/packages/analyzer/test/src/context/mock_sdk.dart
+++ b/packages/analyzer/test/src/context/mock_sdk.dart
@@ -118,15 +118,23 @@
 
 import 'dart:math';
 
+part 'stream.dart';
+
 class Future<T> {
   factory Future.delayed(Duration duration, [T computation()]) => null;
   factory Future.value([value]) => null;
   static Future wait(List<Future> futures) => null;
 }
-
+''',
+      const <_MockSdkFile>[
+    const _MockSdkFile(
+        '/lib/async/stream.dart',
+        r'''
+part of dart.async;
 class Stream<T> {}
 abstract class StreamTransformer<S, T> {}
-''');
+''')
+  ]);
 
   static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
       'dart:collection',
@@ -197,6 +205,9 @@
   MockSdk() {
     LIBRARIES.forEach((_MockSdkLibrary library) {
       provider.newFile(library.path, library.content);
+      library.parts.forEach((file) {
+        provider.newFile(file.path, file.content);
+      });
     });
   }
 
@@ -280,6 +291,7 @@
       "dart:core": "/lib/core/core.dart",
       "dart:html": "/lib/html/dartium/html_dartium.dart",
       "dart:async": "/lib/async/async.dart",
+      "dart:async/stream.dart": "/lib/async/stream.dart",
       "dart:collection": "/lib/collection/collection.dart",
       "dart:convert": "/lib/convert/convert.dart",
       "dart:math": "/lib/math/math.dart"
@@ -302,8 +314,10 @@
   final String shortName;
   final String path;
   final String content;
+  final List<_MockSdkFile> parts;
 
-  const _MockSdkLibrary(this.shortName, this.path, this.content);
+  const _MockSdkLibrary(this.shortName, this.path, this.content,
+      [this.parts = const <_MockSdkFile>[]]);
 
   @override
   String get category => throw unimplemented;
@@ -329,6 +343,13 @@
   UnimplementedError get unimplemented => new UnimplementedError();
 }
 
+class _MockSdkFile {
+  final String path;
+  final String content;
+
+  const _MockSdkFile(this.path, this.content);
+}
+
 /**
  * An [AnalysisContextImpl] that only contains sources for a Dart SDK.
  */
diff --git a/packages/analyzer/test/src/task/dart_test.dart b/packages/analyzer/test/src/task/dart_test.dart
index 0f39004..547df97 100644
--- a/packages/analyzer/test/src/task/dart_test.dart
+++ b/packages/analyzer/test/src/task/dart_test.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/html.dart';
+import 'package:analyzer/src/task/strong/info.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/general.dart';
 import 'package:analyzer/task/model.dart';
@@ -65,6 +66,7 @@
   runReflectiveTests(ResolveVariableReferencesTaskTest);
   runReflectiveTests(ScanDartTaskTest);
   runReflectiveTests(StrongModeInferenceTest);
+  runReflectiveTests(StrongModeVerifyUnitTaskTest);
   runReflectiveTests(VerifyUnitTaskTest);
 }
 
@@ -124,6 +126,8 @@
 isInstanceOf isResolveVariableReferencesTask =
     new isInstanceOf<ResolveVariableReferencesTask>();
 isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>();
+isInstanceOf isStrongModeVerifyUnitTask =
+    new isInstanceOf<StrongModeVerifyUnitTask>();
 isInstanceOf isVerifyUnitTask = new isInstanceOf<VerifyUnitTask>();
 
 final LintCode _testLintCode = new LintCode('test lint', 'test lint code');
@@ -1263,7 +1267,7 @@
     expect(evaluationResult.value.type, isNotNull);
     expect(evaluationResult.value.type.name, 'D');
     expect(evaluationResult.value.fields, contains('value'));
-    expect(evaluationResult.value.fields['value'].intValue, 1);
+    expect(evaluationResult.value.fields['value'].toIntValue(), 1);
   }
 
   test_annotation_without_args() {
@@ -1281,7 +1285,7 @@
     // And check that it has the expected value.
     expect(evaluationResult, isNotNull);
     expect(evaluationResult.value, isNotNull);
-    expect(evaluationResult.value.intValue, 1);
+    expect(evaluationResult.value.toIntValue(), 1);
   }
 
   test_circular_reference() {
@@ -1338,7 +1342,7 @@
 ''');
     expect(evaluationResult, isNotNull);
     expect(evaluationResult.value, isNotNull);
-    expect(evaluationResult.value.intValue, 2);
+    expect(evaluationResult.value.toIntValue(), 2);
   }
 
   test_external_const_factory() {
@@ -1364,7 +1368,7 @@
 ''');
     expect(evaluationResult, isNotNull);
     expect(evaluationResult.value, isNotNull);
-    expect(evaluationResult.value.intValue, 1);
+    expect(evaluationResult.value.toIntValue(), 1);
   }
 
   void _checkCircularities(
@@ -1844,8 +1848,9 @@
 const x = const C();
 ''');
     LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
-    computeResult(target, RESOLVED_UNIT, matcher: isEvaluateUnitConstantsTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT];
+    computeResult(target, RESOLVED_UNIT10,
+        matcher: isEvaluateUnitConstantsTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT10];
     CompilationUnitElement unitElement = unit.element;
     expect(
         (unitElement.types[0].constructors[0] as ConstructorElementImpl)
@@ -1907,7 +1912,7 @@
   UsedLocalElements usedElements;
   Set<String> usedElementNames;
 
-  fail_perform_forPart_afterLibraryUpdate() {
+  test_perform_forPart_afterLibraryUpdate() {
     Source libSource = newSource(
         '/my_lib.dart',
         '''
@@ -2249,11 +2254,12 @@
   void setUp() {
     super.setUp();
     enableLints();
+    setLints(context, [new GenerateLintsTaskTest_TestLinter()]);
   }
 
   @override
   void tearDown() {
-    LintGenerator.LINTERS.clear();
+    setLints(context, []);
     super.tearDown();
   }
 
@@ -2264,9 +2270,6 @@
 class a { }
 ''');
 
-    LintGenerator.LINTERS.clear();
-    LintGenerator.LINTERS.add(new GenerateLintsTaskTest_TestLinter());
-
     LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
     computeResult(target, LINTS, matcher: isGenerateLintsTask);
     // validate
@@ -3972,6 +3975,59 @@
 }
 
 @reflectiveTest
+class StrongModeVerifyUnitTaskTest extends _AbstractDartTaskTest {
+  @override
+  void setUp() {
+    super.setUp();
+    enableStrongMode();
+  }
+
+  void test_perform_recordDynamicInvoke() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+void main() {
+  dynamic a = [];
+  a[0];
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), STRONG_MODE_ERRORS);
+    CompilationUnit unit = outputs[RESOLVED_UNIT];
+
+    // validate
+    _fillErrorListener(STRONG_MODE_ERRORS);
+    expect(errorListener.errors, isEmpty);
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "main");
+    ExpressionStatement statement = statements[1];
+    IndexExpression idx = statement.expression;
+    expect(DynamicInvoke.get(idx.target), isNotNull);
+    expect(DynamicInvoke.get(idx.target), isNotNull);
+    expect(DynamicInvoke.get(idx.target), isTrue);
+  }
+
+  void test_perform_verifyError() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+int topLevel = 3;
+class C {
+  String field = topLevel;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), STRONG_MODE_ERRORS);
+    // validate
+    _fillErrorListener(STRONG_MODE_ERRORS);
+
+    var errors = errorListener.errors;
+    expect(errors.length, 1);
+    expect(errors[0].errorCode.name, "dev_compiler.StaticTypeError");
+  }
+}
+
+@reflectiveTest
 class VerifyUnitTaskTest extends _AbstractDartTaskTest {
   test_perform_constantError() {
     Source source = newSource(
@@ -4017,8 +4073,10 @@
     computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
     // validate
     _fillErrorListener(VERIFY_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+
+    var errors = errorListener.errors;
+    expect(errors.length, 1);
+    expect(errors[0].errorCode, StaticTypeWarningCode.INVALID_ASSIGNMENT);
   }
 
   test_perform_verifyError() {
diff --git a/packages/analyzer/test/src/task/dart_work_manager_test.dart b/packages/analyzer/test/src/task/dart_work_manager_test.dart
index e15aa7b..8dd7dbc 100644
--- a/packages/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/packages/analyzer/test/src/task/dart_work_manager_test.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/generated/error.dart' show AnalysisError;
 import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
 import 'package:analyzer/src/generated/scanner.dart' show ScannerErrorCode;
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/task/dart.dart';
@@ -331,6 +332,32 @@
     expect(manager.getLibrariesContainingPart(part3), isEmpty);
   }
 
+  void test_getLibrariesContainingPart_inSDK() {
+    Source part = new _SourceMock('part.dart');
+    when(part.isInSystemLibrary).thenReturn(true);
+    // SDK work manager
+    DartWorkManager sdkDartWorkManagerMock = new _DartWorkManagerMock();
+    when(sdkDartWorkManagerMock.getLibrariesContainingPart(part))
+        .thenReturn([source2, source3]);
+    // SDK context mock
+    InternalAnalysisContext sdkContextMock = new _InternalAnalysisContextMock();
+    when(sdkContextMock.workManagers).thenReturn([sdkDartWorkManagerMock]);
+    // SDK mock
+    DartSdk sdkMock = new _DartSdkMock();
+    when(sdkMock.context).thenReturn(sdkContextMock);
+    // SourceFactory mock
+    SourceFactory sourceFactory = new _SourceFactoryMock();
+    when(sourceFactory.dartSdk).thenReturn(sdkMock);
+    when(context.sourceFactory).thenReturn(sourceFactory);
+    // SDK source mock
+    Source source = new _SourceMock('test.dart');
+    when(source.source).thenReturn(source);
+    when(source.isInSystemLibrary).thenReturn(true);
+    // validate
+    expect(manager.getLibrariesContainingPart(part),
+        unorderedEquals([source2, source3]));
+  }
+
   void test_getNextResult_hasLibraries_firstIsError() {
     entry1.setErrorState(caughtException, [LIBRARY_ERRORS_READY]);
     manager.librarySourceQueue.addAll([source1, source2]);
@@ -604,6 +631,28 @@
     expect(cache.getState(part1, CONTAINING_LIBRARIES), CacheState.INVALID);
   }
 
+  void test_resultsComputed_inSDK() {
+    DartWorkManager sdkDartWorkManagerMock = new _DartWorkManagerMock();
+    // SDK context mock
+    InternalAnalysisContext sdkContextMock = new _InternalAnalysisContextMock();
+    when(sdkContextMock.workManagers).thenReturn([sdkDartWorkManagerMock]);
+    // SDK mock
+    DartSdk sdkMock = new _DartSdkMock();
+    when(sdkMock.context).thenReturn(sdkContextMock);
+    // SourceFactory mock
+    SourceFactory sourceFactory = new _SourceFactoryMock();
+    when(sourceFactory.dartSdk).thenReturn(sdkMock);
+    when(context.sourceFactory).thenReturn(sourceFactory);
+    // SDK source mock
+    Source source = new _SourceMock('test.dart');
+    when(source.source).thenReturn(source);
+    when(source.isInSystemLibrary).thenReturn(true);
+    // notify and validate
+    Map<ResultDescriptor, dynamic> outputs = <ResultDescriptor, dynamic>{};
+    manager.resultsComputed(source, outputs);
+    verify(sdkDartWorkManagerMock.resultsComputed(source, outputs)).once();
+  }
+
   void test_resultsComputed_noSourceKind() {
     manager.unknownSourceQueue.addAll([source1, source2]);
     manager.resultsComputed(source1, {});
@@ -706,6 +755,14 @@
   }
 }
 
+class _DartSdkMock extends TypedMock implements DartSdk {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _DartWorkManagerMock extends TypedMock implements DartWorkManager {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
 class _InternalAnalysisContextMock extends TypedMock
     implements InternalAnalysisContext {
   @override
@@ -739,3 +796,17 @@
 
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
+
+class _SourceFactoryMock extends TypedMock implements SourceFactory {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _SourceMock extends TypedMock implements Source {
+  final String shortName;
+  _SourceMock(this.shortName);
+  @override
+  String get fullName => '/' + shortName;
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+  @override
+  String toString() => fullName;
+}
diff --git a/packages/analyzer/test/src/task/html_test.dart b/packages/analyzer/test/src/task/html_test.dart
index 7d8da56..a901165 100644
--- a/packages/analyzer/test/src/task/html_test.dart
+++ b/packages/analyzer/test/src/task/html_test.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/task/general.dart';
 import 'package:analyzer/task/html.dart';
 import 'package:analyzer/task/model.dart';
+import 'package:html/dom.dart';
 import 'package:unittest/unittest.dart';
 
 import '../../reflective_tests.dart';
@@ -228,7 +229,7 @@
         r'''
 <html>
   <head>
-    <title>test page</title>
+    <title>test page</not-title>
   </head>
   <body>
     Test
@@ -335,4 +336,33 @@
       }
     }
   }
+
+  test_perform_noDocType() {
+    String code = r'''
+<div>AAA</div>
+<span>BBB</span>
+''';
+    AnalysisTarget target = newSource('/test.html', code);
+    computeResult(target, HTML_DOCUMENT);
+    expect(task, isParseHtmlTask);
+    // validate Document
+    {
+      Document document = outputs[HTML_DOCUMENT];
+      expect(document, isNotNull);
+      // artificial <html>
+      expect(document.nodes, hasLength(1));
+      Element htmlElement = document.nodes[0];
+      expect(htmlElement.localName, 'html');
+      // artificial <body>
+      expect(htmlElement.nodes, hasLength(2));
+      Element bodyElement = htmlElement.nodes[1];
+      expect(bodyElement.localName, 'body');
+      // actual nodes
+      expect(bodyElement.nodes, hasLength(4));
+      expect((bodyElement.nodes[0] as Element).localName, 'div');
+      expect((bodyElement.nodes[2] as Element).localName, 'span');
+    }
+    // it's OK to don't have DOCTYPE
+    expect(outputs[HTML_DOCUMENT_ERRORS], isEmpty);
+  }
 }
diff --git a/packages/analyzer/test/src/task/strong/checker_test.dart b/packages/analyzer/test/src/task/strong/checker_test.dart
new file mode 100644
index 0000000..874916c
--- /dev/null
+++ b/packages/analyzer/test/src/task/strong/checker_test.dart
@@ -0,0 +1,2311 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this file needs to be refactored, it's a port from
+// package:dev_compiler's tests
+/// General type checking tests
+library test.src.task.strong.checker_test;
+
+import 'package:unittest/unittest.dart';
+
+import 'strong_test_helper.dart';
+
+void main() {
+  testChecker('ternary operator', {
+    '/main.dart': '''
+        abstract class Comparable<T> {
+          int compareTo(T other);
+          static int compare(Comparable a, Comparable b) => a.compareTo(b);
+        }
+        typedef int Comparator<T>(T a, T b);
+
+        typedef bool _Predicate<T>(T value);
+
+        class SplayTreeMap<K, V> {
+          Comparator<K> _comparator;
+          _Predicate _validKey;
+
+          // Initializing _comparator needs a cast, since K may not always be
+          // Comparable.
+          // Initializing _validKey shouldn't need a cast.  Currently
+          // it requires inference to work because of dartbug.com/23381
+          SplayTreeMap([int compare(K key1, K key2),
+                        bool isValidKey(potentialKey)]) {
+            : _comparator = /*warning:DownCastComposite*/(compare == null) ? Comparable.compare : compare,
+              _validKey = /*info:InferredType should be pass*/(isValidKey != null) ? isValidKey : ((v) => true);
+              _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey != null) ? isValidKey : ((v) => true);
+              _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v : ((v) => true);
+          }
+        }
+        void main() {
+          Object obj = 42;
+          dynamic dyn = 42;
+          int i = 42;
+
+          // Check the boolean conversion of the condition.
+          print((/*severe:StaticTypeError*/i) ? false : true);
+          print((/*info:DownCastImplicit*/obj) ? false : true);
+          print((/*info:DynamicCast*/dyn) ? false : true);
+        }
+      '''
+  });
+
+  testChecker('if/for/do/while statements use boolean conversion', {
+    '/main.dart': '''
+      main() {
+        dynamic d = 42;
+        Object obj = 42;
+        int i = 42;
+        bool b = false;
+
+        if (b) {}
+        if (/*info:DynamicCast*/dyn) {}
+        if (/*info:DownCastImplicit*/obj) {}
+        if (/*severe:StaticTypeError*/i) {}
+
+        while (b) {}
+        while (/*info:DynamicCast*/dyn) {}
+        while (/*info:DownCastImplicit*/obj) {}
+        while (/*severe:StaticTypeError*/i) {}
+
+        do {} while (b);
+        do {} while (/*info:DynamicCast*/dyn);
+        do {} while (/*info:DownCastImplicit*/obj);
+        do {} while (/*severe:StaticTypeError*/i);
+
+        for (;b;) {}
+        for (;/*info:DynamicCast*/dyn;) {}
+        for (;/*info:DownCastImplicit*/obj;) {}
+        for (;/*severe:StaticTypeError*/i;) {}
+      }
+    '''
+  });
+
+  testChecker('dynamic invocation', {
+    '/main.dart': '''
+
+      class A {
+        dynamic call(dynamic x) => x;
+      }
+      class B extends A {
+        int call(int x) => x;
+        double col(double x) => x;
+      }
+      void main() {
+        {
+          B f = new B();
+          int x;
+          double y;
+          // The analyzer has what I believe is a bug (dartbug.com/23252) which
+          // causes the return type of calls to f to be treated as dynamic.
+          x = /*info:DynamicCast should be pass*/f(3);
+          x = /*severe:StaticTypeError*/f.col(3.0);
+          y = /*info:DynamicCast should be severe:StaticTypeError*/f(3);
+          y = f.col(3.0);
+          f(/*severe:StaticTypeError*/3.0);
+          f.col(/*severe:StaticTypeError*/3);
+        }
+        {
+          Function f = new B();
+          int x;
+          double y;
+          x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+          x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
+          y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+          y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
+          (/*info:DynamicInvoke*/f(3.0));
+          (/*info:DynamicInvoke*/f.col(3));
+        }
+        {
+          A f = new B();
+          int x;
+          double y;
+          x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+          y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
+          (/*info:DynamicInvoke*/f(3.0));
+        }
+      }
+    '''
+  });
+
+  testChecker('conversion and dynamic invoke', {
+    '/helper.dart': '''
+      dynamic toString = (int x) => x + 42;
+      dynamic hashCode = "hello";
+      ''',
+    '/main.dart': '''
+      import 'helper.dart' as helper;
+
+      class A {
+        String x = "hello world";
+
+        void baz1(y) => x + /*info:DynamicCast*/y;
+        static baz2(y) => /*info:DynamicInvoke*/y + y;
+      }
+
+      void foo(String str) {
+        print(str);
+      }
+
+      class B {
+        String toString([int arg]) => arg.toString();
+      }
+
+      void bar(a) {
+        foo(/*info:DynamicCast,info:DynamicInvoke*/a.x);
+      }
+
+      baz() => new B();
+
+      typedef DynFun(x);
+      typedef StrFun(String x);
+
+      var bar1 = bar;
+
+      void main() {
+        var a = new A();
+        bar(a);
+        (/*info:DynamicInvoke*/bar1(a));
+        var b = bar;
+        (/*info:DynamicInvoke*/b(a));
+        var f1 = foo;
+        f1("hello");
+        dynamic f2 = foo;
+        (/*info:DynamicInvoke*/f2("hello"));
+        DynFun f3 = foo;
+        (/*info:DynamicInvoke*/f3("hello"));
+        (/*info:DynamicInvoke*/f3(42));
+        StrFun f4 = foo;
+        f4("hello");
+        a.baz1("hello");
+        var b1 = a.baz1;
+        (/*info:DynamicInvoke*/b1("hello"));
+        A.baz2("hello");
+        var b2 = A.baz2;
+        (/*info:DynamicInvoke*/b2("hello"));
+
+        dynamic a1 = new B();
+        (/*info:DynamicInvoke*/a1.x);
+        a1.toString();
+        (/*info:DynamicInvoke*/a1.toString(42));
+        var toStringClosure = a1.toString;
+        (/*info:DynamicInvoke*/a1.toStringClosure());
+        (/*info:DynamicInvoke*/a1.toStringClosure(42));
+        (/*info:DynamicInvoke*/a1.toStringClosure("hello"));
+        a1.hashCode;
+
+        dynamic toString = () => null;
+        (/*info:DynamicInvoke*/toString());
+
+        (/*info:DynamicInvoke*/helper.toString());
+        var toStringClosure2 = helper.toString;
+        (/*info:DynamicInvoke*/toStringClosure2());
+        int hashCode = /*info:DynamicCast*/helper.hashCode;
+
+        baz().toString();
+        baz().hashCode;
+      }
+    '''
+  });
+
+  testChecker('Constructors', {
+    '/main.dart': '''
+      const num z = 25;
+      Object obj = "world";
+
+      class A {
+        int x;
+        String y;
+
+        A(this.x) : this.y = /*severe:StaticTypeError*/42;
+
+        A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCast*/p;
+
+        A.c2(this.x, this.y);
+
+        A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y);
+      }
+
+      class B extends A {
+        B() : super(/*severe:StaticTypeError*/"hello");
+
+        B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y, 
+                                         /*severe:StaticTypeError*/x);
+
+        B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y);
+      }
+
+      void main() {
+         A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z);
+         var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImplicit*/obj);
+      }
+   '''
+  });
+
+  testChecker('Unbound variable', {
+    '/main.dart': '''
+      void main() {
+         dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable;
+      }
+   '''
+  });
+
+  testChecker('Unbound type name', {
+    '/main.dart': '''
+      void main() {
+         /*pass should be severe:StaticTypeError*/AToB y;
+      }
+   '''
+  });
+
+  testChecker('Ground type subtyping: dynamic is top', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      void main() {
+         dynamic y;
+         Object o;
+         int i = 0;
+         double d = 0.0;
+         num n;
+         A a;
+         B b;
+         y = o;
+         y = i;
+         y = d;
+         y = n;
+         y = a;
+         y = b;
+      }
+   '''
+  });
+
+  testChecker('Ground type subtyping: dynamic downcasts', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      void main() {
+         dynamic y;
+         Object o;
+         int i = 0;
+         double d = 0.0;
+         num n;
+         A a;
+         B b;
+         o = y;
+         i = /*info:DynamicCast*/y;
+         d = /*info:DynamicCast*/y;
+         n = /*info:DynamicCast*/y;
+         a = /*info:DynamicCast*/y;
+         b = /*info:DynamicCast*/y;
+      }
+   '''
+  });
+
+  testChecker('Ground type subtyping: assigning a class', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      void main() {
+         dynamic y;
+         Object o;
+         int i = 0;
+         double d = 0.0;
+         num n;
+         A a;
+         B b;
+         y = a;
+         o = a;
+         i = /*severe:StaticTypeError*/a;
+         d = /*severe:StaticTypeError*/a;
+         n = /*severe:StaticTypeError*/a;
+         a = a;
+         b = /*info:DownCastImplicit*/a;
+      }
+   '''
+  });
+
+  testChecker('Ground type subtyping: assigning a subclass', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+      class C extends A {}
+
+      void main() {
+         dynamic y;
+         Object o;
+         int i = 0;
+         double d = 0.0;
+         num n;
+         A a;
+         B b;
+         C c;
+         y = b;
+         o = b;
+         i = /*severe:StaticTypeError*/b;
+         d = /*severe:StaticTypeError*/b;
+         n = /*severe:StaticTypeError*/b;
+         a = b;
+         b = b;
+         c = /*severe:StaticTypeError*/b;
+      }
+   '''
+  });
+
+  testChecker('Ground type subtyping: interfaces', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+      class C extends A {}
+      class D extends B implements C {}
+
+      void main() {
+         A top;
+         B left;
+         C right;
+         D bot;
+         {
+           top = top;
+           top = left;
+           top = right;
+           top = bot;
+         }
+         {
+           left = /*info:DownCastImplicit*/top;
+           left = left;
+           left = /*severe:StaticTypeError*/right;
+           left = bot;
+         }
+         {
+           right = /*info:DownCastImplicit*/top;
+           right = /*severe:StaticTypeError*/left;
+           right = right;
+           right = bot;
+         }
+         {
+           bot = /*info:DownCastImplicit*/top;
+           bot = /*info:DownCastImplicit*/left;
+           bot = /*info:DownCastImplicit*/right;
+           bot = bot;
+         }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: int and object', {
+    '/main.dart': '''
+
+      typedef Object Top(int x);      // Top of the lattice
+      typedef int Left(int x);        // Left branch
+      typedef int Left2(int x);       // Left branch
+      typedef Object Right(Object x); // Right branch
+      typedef int Bot(Object x);      // Bottom of the lattice
+
+      Object top(int x) => x;
+      int left(int x) => x;
+      Object right(Object x) => x;
+      int _bot(Object x) => /*info:DownCastImplicit*/x;
+      int bot(Object x) => x as int;
+
+      void main() {
+        { // Check typedef equality
+          Left f = left;
+          Left2 g = f;
+        }
+        {
+          Top f;
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Left f;
+          f = /*warning:DownCastComposite*/top;
+          f = left;
+          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = bot;
+        }
+        {
+          Right f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = right;
+          f = bot;
+        }
+        {
+          Bot f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DownCastComposite*/right;
+          f = bot;
+        }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: classes', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      typedef A Top(B x);   // Top of the lattice
+      typedef B Left(B x);  // Left branch
+      typedef B Left2(B x); // Left branch
+      typedef A Right(A x); // Right branch
+      typedef B Bot(A x);   // Bottom of the lattice
+
+      B left(B x) => x;
+      B _bot(A x) => /*info:DownCastImplicit*/x;
+      B bot(A x) => x as B;
+      A top(B x) => x;
+      A right(A x) => x;
+
+      void main() {
+        { // Check typedef equality
+          Left f = left;
+          Left2 g = f;
+        }
+        {
+          Top f;
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Left f;
+          f = /*warning:DownCastComposite*/top;
+          f = left;
+          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = bot;
+        }
+        {
+          Right f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = right;
+          f = bot;
+        }
+        {
+          Bot f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DownCastComposite*/right;
+          f = bot;
+        }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: dynamic', {
+    '/main.dart': '''
+
+      class A {}
+
+      typedef dynamic Top(dynamic x);     // Top of the lattice
+      typedef dynamic Left(A x);          // Left branch
+      typedef A Right(dynamic x);         // Right branch
+      typedef A Bottom(A x);              // Bottom of the lattice
+
+      dynamic left(A x) => x;
+      A bot(A x) => x;
+      dynamic top(dynamic x) => x;
+      A right(dynamic x) => /*info:DynamicCast*/x;
+
+      void main() {
+        {
+          Top f;
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Left f;
+          f = /*warning:DownCastComposite*/top;
+          f = left;
+          f = /*warning:DownCastComposite*/right;
+          f = bot;
+        }
+        {
+          Right f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+          f = right;
+          f = bot;
+        }
+        {
+          Bottom f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DownCastComposite*/right;
+          f = bot;
+        }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: function literal variance', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      typedef T Function2<S, T>(S z);
+
+      A top(B x) => x;
+      B left(B x) => x;
+      A right(A x) => x;
+      B bot(A x) => x as B;
+
+      void main() {
+        {
+          Function2<B, A> f;
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<B, B> f;
+          f = /*warning:DownCastComposite*/top;
+          f = left;
+          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = bot;
+        }
+        {
+          Function2<A, A> f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<A, B> f;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DownCastComposite*/right;
+          f = bot;
+        }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: function variable variance', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      typedef T Function2<S, T>(S z);
+
+      void main() {
+        {
+          Function2<B, A> top;
+          Function2<B, B> left;
+          Function2<A, A> right;
+          Function2<A, B> bot;
+
+          top = right;
+          top = bot;
+          top = top;
+          top = left;
+
+          left = /*warning:DownCastComposite*/top;
+          left = left;
+          left = /*warning:DownCastComposite*/right; // Should we reject this?
+          left = bot;
+
+          right = /*warning:DownCastComposite*/top;
+          right = /*warning:DownCastComposite*/left; // Should we reject this?
+          right = right;
+          right = bot;
+
+          bot = /*warning:DownCastComposite*/top;
+          bot = /*warning:DownCastComposite*/left;
+          bot = /*warning:DownCastComposite*/right;
+          bot = bot;
+        }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: higher order function literals', {
+    '/main.dart': '''
+
+      class A {}
+      class B extends A {}
+
+      typedef T Function2<S, T>(S z);
+
+      typedef A BToA(B x);  // Top of the base lattice
+      typedef B AToB(A x);  // Bot of the base lattice
+
+      BToA top(AToB f) => f;
+      AToB left(AToB f) => f;
+      BToA right(BToA f) => f;
+      AToB _bot(BToA f) => /*warning:DownCastComposite*/f;
+      AToB bot(BToA f) => f as AToB;
+
+      Function2<B, A> top(AToB f) => f;
+      Function2<A, B> left(AToB f) => f;
+      Function2<B, A> right(BToA f) => f;
+      Function2<A, B> _bot(BToA f) => /*warning:DownCastComposite*/f;
+      Function2<A, B> bot(BToA f) => f as Function2<A, B>;
+
+
+      BToA top(Function2<A, B> f) => f;
+      AToB left(Function2<A, B> f) => f;
+      BToA right(Function2<B, A> f) => f;
+      AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f;
+      AToB bot(Function2<B, A> f) => f as AToB;
+
+      void main() {
+        {
+          Function2<AToB, BToA> f; // Top
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<AToB, AToB> f; // Left
+          f = /*warning:DownCastComposite*/top;
+          f = left;
+          f = /*warning:DownCastComposite*/right; // Should we reject this?
+          f = bot;
+        }
+        {
+          Function2<BToA, BToA> f; // Right
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left; // Should we reject this?
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<BToA, AToB> f; // Bot
+          f = bot;
+          f = /*warning:DownCastComposite*/left;
+          f = /*warning:DownCastComposite*/top;
+          f = /*warning:DownCastComposite*/left;
+        }
+      }
+   '''
+  });
+
+  testChecker(
+      'Function typing and subtyping: higher order function variables', {
+    '/main.dart': '''
+
+    class A {}
+    class B extends A {}
+
+    typedef T Function2<S, T>(S z);
+
+    void main() {
+      {
+        Function2<Function2<A, B>, Function2<B, A>> top;
+        Function2<Function2<B, A>, Function2<B, A>> right;
+        Function2<Function2<A, B>, Function2<A, B>> left;
+        Function2<Function2<B, A>, Function2<A, B>> bot;
+
+        top = right;
+        top = bot;
+        top = top;
+        top = left;
+
+        left = /*warning:DownCastComposite*/top;
+        left = left;
+        left =
+            /*warning:DownCastComposite should be severe:StaticTypeError*/right;
+        left = bot;
+
+        right = /*warning:DownCastComposite*/top;
+        right =
+            /*warning:DownCastComposite should be severe:StaticTypeError*/left;
+        right = right;
+        right = bot;
+
+        bot = /*warning:DownCastComposite*/top;
+        bot = /*warning:DownCastComposite*/left;
+        bot = /*warning:DownCastComposite*/right;
+        bot = bot;
+      }
+    }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: named and optional parameters', {
+    '/main.dart': '''
+
+      class A {}
+
+      typedef A FR(A x);
+      typedef A FO([A x]);
+      typedef A FN({A x});
+      typedef A FRR(A x, A y);
+      typedef A FRO(A x, [A y]);
+      typedef A FRN(A x, {A n});
+      typedef A FOO([A x, A y]);
+      typedef A FNN({A x, A y});
+      typedef A FNNN({A z, A y, A x});
+
+      void main() {
+         FR r;
+         FO o;
+         FN n;
+         FRR rr;
+         FRO ro;
+         FRN rn;
+         FOO oo;
+         FNN nn;
+         FNNN nnn;
+
+         r = r;
+         r = o;
+         r = /*severe:StaticTypeError*/n;
+         r = /*severe:StaticTypeError*/rr;
+         r = ro;
+         r = rn;
+         r = oo;
+         r = /*severe:StaticTypeError*/nn;
+         r = /*severe:StaticTypeError*/nnn;
+
+         o = /*warning:DownCastComposite*/r;
+         o = o;
+         o = /*severe:StaticTypeError*/n;
+         o = /*severe:StaticTypeError*/rr;
+         o = /*severe:StaticTypeError*/ro;
+         o = /*severe:StaticTypeError*/rn;
+         o = oo;
+         o = /*severe:StaticTypeError*/nn
+         o = /*severe:StaticTypeError*/nnn;
+
+         n = /*severe:StaticTypeError*/r;
+         n = /*severe:StaticTypeError*/o;
+         n = n;
+         n = /*severe:StaticTypeError*/rr;
+         n = /*severe:StaticTypeError*/ro;
+         n = /*severe:StaticTypeError*/rn;
+         n = /*severe:StaticTypeError*/oo;
+         n = nn;
+         n = nnn;
+
+         rr = /*severe:StaticTypeError*/r;
+         rr = /*severe:StaticTypeError*/o;
+         rr = /*severe:StaticTypeError*/n;
+         rr = rr;
+         rr = ro;
+         rr = /*severe:StaticTypeError*/rn;
+         rr = oo;
+         rr = /*severe:StaticTypeError*/nn;
+         rr = /*severe:StaticTypeError*/nnn;
+
+         ro = /*warning:DownCastComposite*/r;
+         ro = /*severe:StaticTypeError*/o;
+         ro = /*severe:StaticTypeError*/n;
+         ro = /*warning:DownCastComposite*/rr;
+         ro = ro;
+         ro = /*severe:StaticTypeError*/rn;
+         ro = oo;
+         ro = /*severe:StaticTypeError*/nn;
+         ro = /*severe:StaticTypeError*/nnn;
+
+         rn = /*warning:DownCastComposite*/r;
+         rn = /*severe:StaticTypeError*/o;
+         rn = /*severe:StaticTypeError*/n;
+         rn = /*severe:StaticTypeError*/rr;
+         rn = /*severe:StaticTypeError*/ro;
+         rn = rn;
+         rn = /*severe:StaticTypeError*/oo;
+         rn = /*severe:StaticTypeError*/nn;
+         rn = /*severe:StaticTypeError*/nnn;
+
+         oo = /*warning:DownCastComposite*/r;
+         oo = /*warning:DownCastComposite*/o;
+         oo = /*severe:StaticTypeError*/n;
+         oo = /*warning:DownCastComposite*/rr;
+         oo = /*warning:DownCastComposite*/ro;
+         oo = /*severe:StaticTypeError*/rn;
+         oo = oo;
+         oo = /*severe:StaticTypeError*/nn;
+         oo = /*severe:StaticTypeError*/nnn;
+
+         nn = /*severe:StaticTypeError*/r;
+         nn = /*severe:StaticTypeError*/o;
+         nn = /*warning:DownCastComposite*/n;
+         nn = /*severe:StaticTypeError*/rr;
+         nn = /*severe:StaticTypeError*/ro;
+         nn = /*severe:StaticTypeError*/rn;
+         nn = /*severe:StaticTypeError*/oo;
+         nn = nn;
+         nn = nnn;
+
+         nnn = /*severe:StaticTypeError*/r;
+         nnn = /*severe:StaticTypeError*/o;
+         nnn = /*warning:DownCastComposite*/n;
+         nnn = /*severe:StaticTypeError*/rr;
+         nnn = /*severe:StaticTypeError*/ro;
+         nnn = /*severe:StaticTypeError*/rn;
+         nnn = /*severe:StaticTypeError*/oo;
+         nnn = /*warning:DownCastComposite*/nn;
+         nnn = nnn;
+      }
+   '''
+  });
+
+  testChecker('Function subtyping: objects with call methods', {
+    '/main.dart': '''
+
+      typedef int I2I(int x);
+      typedef num N2N(num x);
+      class A {
+         int call(int x) => x;
+      }
+      class B {
+         num call(num x) => x;
+      }
+      int i2i(int x) => x;
+      num n2n(num x) => x;
+      void main() {
+         {
+           I2I f;
+           f = new A();
+           f = /*severe:StaticTypeError*/new B();
+           f = i2i;
+           f = /*warning:DownCastComposite*/n2n;
+           f = /*warning:DownCastComposite*/i2i as Object;
+           f = /*warning:DownCastComposite*/n2n as Function;
+         }
+         {
+           N2N f;
+           f = /*severe:StaticTypeError*/new A();
+           f = new B();
+           f = /*warning:DownCastComposite*/i2i;
+           f = n2n;
+           f = /*warning:DownCastComposite*/i2i as Object;
+           f = /*warning:DownCastComposite*/n2n as Function;
+         }
+         {
+           A f;
+           f = new A();
+           f = /*severe:StaticTypeError*/new B();
+           f = /*severe:StaticTypeError*/i2i;
+           f = /*severe:StaticTypeError*/n2n;
+           f = /*info:DownCastImplicit*/i2i as Object;
+           f = /*info:DownCastImplicit*/n2n as Function;
+         }
+         {
+           B f;
+           f = /*severe:StaticTypeError*/new A();
+           f = new B();
+           f = /*severe:StaticTypeError*/i2i;
+           f = /*severe:StaticTypeError*/n2n;
+           f = /*info:DownCastImplicit*/i2i as Object;
+           f = /*info:DownCastImplicit*/n2n as Function;
+         }
+         {
+           Function f;
+           f = new A();
+           f = new B();
+           f = i2i;
+           f = n2n;
+           f = /*info:DownCastImplicit*/i2i as Object;
+           f = (n2n as Function);
+         }
+      }
+   '''
+  });
+
+  testChecker('Function typing and subtyping: void', {
+    '/main.dart': '''
+
+      class A {
+        void bar() => null;
+        void foo() => bar; // allowed
+      }
+   '''
+  });
+
+  testChecker('Relaxed casts', {
+    '/main.dart': '''
+
+      class A {}
+
+      class L<T> {}
+      class M<T> extends L<T> {}
+      //     L<dynamic|Object>
+      //    /              \
+      // M<dynamic|Object>  L<A>
+      //    \              /
+      //          M<A>
+      // In normal Dart, there are additional edges
+      //  from M<A> to M<dynamic>
+      //  from L<A> to M<dynamic>
+      //  from L<A> to L<dynamic>
+      void main() {
+        L lOfDs;
+        L<Object> lOfOs;
+        L<A> lOfAs;
+
+        M mOfDs;
+        M<Object> mOfOs;
+        M<A> mOfAs;
+
+        {
+          lOfDs = mOfDs;
+          lOfDs = mOfOs;
+          lOfDs = mOfAs;
+          lOfDs = lOfDs;
+          lOfDs = lOfOs;
+          lOfDs = lOfAs;
+        }
+        {
+          lOfOs = mOfDs;
+          lOfOs = mOfOs;
+          lOfOs = mOfAs;
+          lOfOs = lOfDs;
+          lOfOs = lOfOs;
+          lOfOs = lOfAs;
+        }
+        {
+          lOfAs = /*warning:DownCastComposite*/mOfDs;
+          lOfAs = /*severe:StaticTypeError*/mOfOs;
+          lOfAs = mOfAs;
+          lOfAs = /*warning:DownCastComposite*/lOfDs;
+          lOfAs = /*warning:DownCastComposite*/lOfOs;
+          lOfAs = lOfAs;
+        }
+        {
+          mOfDs = mOfDs;
+          mOfDs = mOfOs;
+          mOfDs = mOfAs;
+          mOfDs = /*info:DownCastImplicit*/lOfDs;
+          mOfDs = /*info:DownCastImplicit*/lOfOs;
+          mOfDs = /*info:DownCastImplicit*/lOfAs;
+        }
+        {
+          mOfOs = mOfDs;
+          mOfOs = mOfOs;
+          mOfOs = mOfAs;
+          mOfOs = /*info:DownCastImplicit*/lOfDs;
+          mOfOs = /*info:DownCastImplicit*/lOfOs;
+          mOfOs = /*severe:StaticTypeError*/lOfAs;
+        }
+        {
+          mOfAs = /*warning:DownCastComposite*/mOfDs;
+          mOfAs = /*warning:DownCastComposite*/mOfOs;
+          mOfAs = mOfAs;
+          mOfAs = /*warning:DownCastComposite*/lOfDs;
+          mOfAs = /*warning:DownCastComposite*/lOfOs;
+          mOfAs = /*warning:DownCastComposite*/lOfAs;
+        }
+
+      }
+   '''
+  });
+
+  testChecker('Type checking literals', {
+    '/main.dart': '''
+          test() {
+            num n = 3;
+            int i = 3;
+            String s = "hello";
+            {
+               List<int> l = <int>[i];
+               l = <int>[/*severe:StaticTypeError*/s];
+               l = <int>[/*info:DownCastImplicit*/n];
+               l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError*/s];
+            }
+            {
+               List l = [i];
+               l = [s];
+               l = [n];
+               l = [i, n, s];
+            }
+            {
+               Map<String, int> m = <String, int>{s: i};
+               m = <String, int>{s: /*severe:StaticTypeError*/s};
+               m = <String, int>{s: /*info:DownCastImplicit*/n};
+               m = <String, int>{s: i,
+                                 s: /*info:DownCastImplicit*/n,
+                                 s: /*severe:StaticTypeError*/s};
+            }
+           // TODO(leafp): We can't currently test for key errors since the
+           // error marker binds to the entire entry.
+            {
+               Map m = {s: i};
+               m = {s: s};
+               m = {s: n};
+               m = {s: i,
+                    s: n,
+                    s: s};
+               m = {i: s,
+                    n: s,
+                    s: s};
+            }
+          }
+   '''
+  });
+
+  testChecker('casts in constant contexts', {
+    '/main.dart': '''
+          class A {
+            static const num n = 3.0;
+            static const int i = /*info:AssignmentCast*/n;
+            final int fi;
+            const A(num a) : this.fi = /*info:DownCastImplicit*/a;
+          }
+          class B extends A {
+            const B(Object a) : super(/*info:DownCastImplicit*/a);
+          }
+          void foo(Object o) {
+            var a = const A(/*info:DownCastImplicit*/o);
+          }
+     '''
+  });
+
+  testChecker('casts in conditionals', {
+    '/main.dart': '''
+          main() {
+            bool b = true;
+            num x = b ? 1 : 2.3;
+            int y = /*info:AssignmentCast*/b ? 1 : 2.3;
+            String z = !b ? "hello" : null;
+            z = b ? null : "hello";
+          }
+      '''
+  });
+
+  testChecker('redirecting constructor', {
+    '/main.dart': '''
+          class A {
+            A(A x) {}
+            A.two() : this(/*severe:StaticTypeError*/3);
+          }
+       '''
+  });
+
+  testChecker('super constructor', {
+    '/main.dart': '''
+          class A { A(A x) {} }
+          class B extends A {
+            B() : super(/*severe:StaticTypeError*/3);
+          }
+       '''
+  });
+
+  testChecker('field/field override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          class Base {
+            B f1;
+            B f2;
+            B f3;
+            B f4;
+          }
+
+          class Child extends Base {
+            /*severe:InvalidMethodOverride*/A f1; // invalid for getter
+            /*severe:InvalidMethodOverride*/C f2; // invalid for setter
+            var f3;
+            /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+          }
+       '''
+  });
+
+  testChecker('getter/getter override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          abstract class Base {
+            B get f1;
+            B get f2;
+            B get f3;
+            B get f4;
+          }
+
+          class Child extends Base {
+            /*severe:InvalidMethodOverride*/A get f1 => null;
+            C get f2 => null;
+            get f3 => null;
+            /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+          }
+       '''
+  });
+
+  testChecker('field/getter override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          abstract class Base {
+            B f1;
+            B f2;
+            B f3;
+            B f4;
+          }
+
+          class Child extends Base {
+            /*severe:InvalidMethodOverride*/A get f1 => null;
+            C get f2 => null;
+            get f3 => null;
+            /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+          }
+       '''
+  });
+
+  testChecker('setter/setter override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          abstract class Base {
+            void set f1(B value);
+            void set f2(B value);
+            void set f3(B value);
+            void set f4(B value);
+            void set f5(B value);
+          }
+
+          class Child extends Base {
+            void set f1(A value) {}
+            /*severe:InvalidMethodOverride*/void set f2(C value) {}
+            void set f3(value) {}
+            /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+            set f5(B value) {}
+          }
+       '''
+  });
+
+  testChecker('field/setter override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          class Base {
+            B f1;
+            B f2;
+            B f3;
+            B f4;
+            B f5;
+          }
+
+          class Child extends Base {
+            B get f1 => null;
+            B get f2 => null;
+            B get f3 => null;
+            B get f4 => null;
+            B get f5 => null;
+
+            void set f1(A value) {}
+            /*severe:InvalidMethodOverride*/void set f2(C value) {}
+            void set f3(value) {}
+            /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+            set f5(B value) {}
+          }
+       '''
+  });
+
+  testChecker('method override', {
+    '/main.dart': '''
+          class A {}
+          class B extends A {}
+          class C extends B {}
+
+          class Base {
+            B m1(B a);
+            B m2(B a);
+            B m3(B a);
+            B m4(B a);
+            B m5(B a);
+            B m6(B a);
+          }
+
+          class Child extends Base {
+            /*severe:InvalidMethodOverride*/A m1(A value) {}
+            /*severe:InvalidMethodOverride*/C m2(C value) {}
+            /*severe:InvalidMethodOverride*/A m3(C value) {}
+            C m4(A value) {}
+            m5(value) {}
+            /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {}
+          }
+       '''
+  });
+
+  testChecker('unary operators', {
+    '/main.dart': '''
+      class A {
+        A operator ~() {}
+        A operator +(int x) {}
+        A operator -(int x) {}
+        A operator -() {}
+      }
+
+      foo() => new A();
+
+      test() {
+        A a = new A();
+        var c = foo();
+
+        ~a;
+        (/*info:DynamicInvoke*/~d);
+
+        !/*severe:StaticTypeError*/a;
+        !/*info:DynamicCast*/d;
+
+        -a;
+        (/*info:DynamicInvoke*/-d);
+
+        ++a;
+        --a;
+        (/*info:DynamicInvoke*/++d);
+        (/*info:DynamicInvoke*/--d);
+
+        a++;
+        a--;
+        (/*info:DynamicInvoke*/d++);
+        (/*info:DynamicInvoke*/d--);
+      }'''
+  });
+
+  testChecker('binary and index operators', {
+    '/main.dart': '''
+          class A {
+            A operator *(B b) {}
+            A operator /(B b) {}
+            A operator ~/(B b) {}
+            A operator %(B b) {}
+            A operator +(B b) {}
+            A operator -(B b) {}
+            A operator <<(B b) {}
+            A operator >>(B b) {}
+            A operator &(B b) {}
+            A operator ^(B b) {}
+            A operator |(B b) {}
+            A operator[](B b) {}
+          }
+
+          class B {
+            A operator -(B b) {}
+          }
+
+          foo() => new A();
+
+          test() {
+            A a = new A();
+            B b = new B();
+            var c = foo();
+            a = a * b;
+            a = a * /*info:DynamicCast*/c;
+            a = a / b;
+            a = a ~/ b;
+            a = a % b;
+            a = a + b;
+            a = a + /*severe:StaticTypeError*/a;
+            a = a - b;
+            b = /*severe:StaticTypeError*/b - b;
+            a = a << b;
+            a = a >> b;
+            a = a & b;
+            a = a ^ b;
+            a = a | b;
+            c = (/*info:DynamicInvoke*/c + b);
+
+            String x = 'hello';
+            int y = 42;
+            x = x + x;
+            x = x + /*info:DynamicCast*/c;
+            x = x + /*severe:StaticTypeError*/y;
+
+            bool p = true;
+            p = p && p;
+            p = p && /*info:DynamicCast*/c;
+            p = (/*info:DynamicCast*/c) && p;
+            p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
+            p = (/*severe:StaticTypeError*/y) && p;
+            p = c == y;
+
+            a = a[b];
+            a = a[/*info:DynamicCast*/c];
+            c = (/*info:DynamicInvoke*/c[b]);
+            a[/*severe:StaticTypeError*/y];
+          }
+       '''
+  });
+
+  testChecker('compound assignments', {
+    '/main.dart': '''
+          class A {
+            A operator *(B b) {}
+            A operator /(B b) {}
+            A operator ~/(B b) {}
+            A operator %(B b) {}
+            A operator +(B b) {}
+            A operator -(B b) {}
+            A operator <<(B b) {}
+            A operator >>(B b) {}
+            A operator &(B b) {}
+            A operator ^(B b) {}
+            A operator |(B b) {}
+            D operator [](B index) {}
+            void operator []=(B index, D value) {}
+          }
+
+          class B {
+            A operator -(B b) {}
+          }
+
+          class D {
+            D operator +(D d) {}
+          }
+
+          foo() => new A();
+
+          test() {
+            int x = 0;
+            x += 5;
+            (/*severe:StaticTypeError*/x += 3.14);
+
+            double y = 0.0;
+            y += 5;
+            y += 3.14;
+
+            num z = 0;
+            z += 5;
+            z += 3.14;
+
+            x = /*info:DownCastImplicit*/x + z;
+            x += /*info:DownCastImplicit*/z;
+            y = /*info:DownCastImplicit*/y + z;
+            y += /*info:DownCastImplicit*/z;
+
+            dynamic w = 42;
+            x += /*info:DynamicCast*/w;
+            y += /*info:DynamicCast*/w;
+            z += /*info:DynamicCast*/w;
+
+            A a = new A();
+            B b = new B();
+            var c = foo();
+            a = a * b;
+            a *= b;
+            a *= /*info:DynamicCast*/c;
+            a /= b;
+            a ~/= b;
+            a %= b;
+            a += b;
+            a += /*severe:StaticTypeError*/a;
+            a -= b;
+            (/*severe:StaticTypeError*/b -= b);
+            a <<= b;
+            a >>= b;
+            a &= b;
+            a ^= b;
+            a |= b;
+            (/*info:DynamicInvoke*/c += b);
+
+            var d = new D();
+            a[b] += d;
+            a[/*info:DynamicCast*/c] += d;
+            a[/*severe:StaticTypeError*/z] += d;
+            a[b] += /*info:DynamicCast*/c;
+            a[b] += /*severe:StaticTypeError*/z;
+            (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d);
+          }
+       '''
+  });
+
+  testChecker('super call placement', {
+    '/main.dart': '''
+          class Base {
+            var x;
+            Base() : x = print('Base.1') { print('Base.2'); }
+          }
+
+          class Derived extends Base {
+            var y, z;
+            Derived()
+                : y = print('Derived.1'),
+                  /*severe:InvalidSuperInvocation*/super(),
+                  z = print('Derived.2') {
+              print('Derived.3');
+            }
+          }
+
+          class Valid extends Base {
+            var y, z;
+            Valid()
+                : y = print('Valid.1'),
+                  z = print('Valid.2'),
+                  super() {
+              print('Valid.3');
+            }
+          }
+
+          class AlsoValid extends Base {
+            AlsoValid() : super();
+          }
+
+          main() => new Derived();
+       '''
+  });
+
+  testChecker('for loop variable', {
+    '/main.dart': '''
+          foo() {
+            for (int i = 0; i < 10; i++) {
+              i = /*severe:StaticTypeError*/"hi";
+            }
+          }
+          bar() {
+            for (var i = 0; i < 10; i++) {
+              int j = i + 1;
+            }
+          }
+        '''
+  });
+
+  group('invalid overrides', () {
+    testChecker('child override', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+                A f;
+            }
+
+            class T1 extends Base {
+              /*severe:InvalidMethodOverride*/B get f => null;
+            }
+
+            class T2 extends Base {
+              /*severe:InvalidMethodOverride*/set f(B b) => null;
+            }
+
+            class T3 extends Base {
+              /*severe:InvalidMethodOverride*/final B f;
+            }
+            class T4 extends Base {
+              // two: one for the getter one for the setter.
+              /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+            }
+         '''
+    });
+
+    testChecker('child override 2', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+                m(A a) {}
+            }
+
+            class Test extends Base {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+            }
+         '''
+    });
+    testChecker('grandchild override', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Grandparent {
+                m(A a) {}
+            }
+            class Parent extends Grandparent {
+            }
+
+            class Test extends Parent {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+            }
+         '''
+    });
+
+    testChecker('double override', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Grandparent {
+                m(A a) {}
+            }
+            class Parent extends Grandparent {
+                m(A a) {}
+            }
+
+            class Test extends Parent {
+                // Reported only once
+                /*severe:InvalidMethodOverride*/m(B a) {}
+            }
+         '''
+    });
+
+    testChecker('double override 2', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Grandparent {
+                m(A a) {}
+            }
+            class Parent extends Grandparent {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+            }
+
+            class Test extends Parent {
+                m(B a) {}
+            }
+         '''
+    });
+
+    testChecker('mixin override to base', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+                m(A a) {}
+            }
+
+            class M1 {
+                m(B a) {}
+            }
+
+            class M2 {}
+
+            class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {}
+            class T2 extends Base with /*severe:InvalidMethodOverride*/M1, M2 {}
+            class T3 extends Base with M2, /*severe:InvalidMethodOverride*/M1 {}
+         '''
+    });
+
+    testChecker('mixin override to mixin', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+            }
+
+            class M1 {
+                m(B a) {}
+            }
+
+            class M2 {
+                m(A a) {}
+            }
+
+            class T1 extends Base with M1, /*severe:InvalidMethodOverride*/M2 {}
+         '''
+    });
+
+    // This is a regression test for a bug in an earlier implementation were
+    // names were hiding errors if the first mixin override looked correct,
+    // but subsequent ones did not.
+    testChecker('no duplicate mixin override', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+                m(A a) {}
+            }
+
+            class M1 {
+                m(A a) {}
+            }
+
+            class M2 {
+                m(B a) {}
+            }
+
+            class M3 {
+                m(B a) {}
+            }
+
+            class T1 extends Base
+                with M1, /*severe:InvalidMethodOverride*/M2, M3 {}
+         '''
+    });
+
+    testChecker('class override of interface', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            abstract class I {
+                m(A a);
+            }
+
+            class T1 implements I {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+            }
+         '''
+    });
+
+    testChecker('base class override to child interface', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            abstract class I {
+                m(A a);
+            }
+
+            class Base {
+                m(B a) {}
+            }
+
+
+            class T1 /*severe:InvalidMethodOverride*/extends Base implements I {
+            }
+         '''
+    });
+
+    testChecker('mixin override of interface', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            abstract class I {
+                m(A a);
+            }
+
+            class M {
+                m(B a) {}
+            }
+
+            class T1 extends Object with /*severe:InvalidMethodOverride*/M
+               implements I {}
+         '''
+    });
+
+    // This is a case were it is incorrect to say that the base class
+    // incorrectly overrides the interface.
+    testChecker(
+        'no errors if subclass correctly overrides base and interface', {
+      '/main.dart': '''
+            class A {}
+            class B {}
+
+            class Base {
+                m(A a) {}
+            }
+
+            class I1 {
+                m(B a) {}
+            }
+
+            class T1 /*severe:InvalidMethodOverride*/extends Base
+                implements I1 {}
+
+            class T2 extends Base implements I1 {
+                /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+            }
+
+            class T3 extends Object with /*severe:InvalidMethodOverride*/Base
+                implements I1 {}
+
+            class T4 extends Object with Base implements I1 {
+                /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+            }
+         '''
+    });
+  });
+
+  group('class override of grand interface', () {
+    testChecker('interface of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 implements I1 {}
+
+              class T1 implements I2 {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+    testChecker('superclass of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 extends I1 {}
+
+              class T1 implements I2 {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+    testChecker('mixin of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class M1 {
+                  m(A a);
+              }
+              abstract class I2 extends Object with M1 {}
+
+              class T1 implements I2 {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+    testChecker('interface of abstract superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class Base implements I1 {}
+
+              class T1 extends Base {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+    testChecker('interface of concrete superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              // See issue #25
+              /*pass should be warning:AnalyzerError*/class Base implements I1 {
+              }
+
+              class T1 extends Base {
+                  // not reported technically because if the class is concrete,
+                  // it should implement all its interfaces and hence it is
+                  // sufficient to check overrides against it.
+                  m(B a) {}
+              }
+           '''
+    });
+  });
+
+  group('mixin override of grand interface', () {
+    testChecker('interface of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 implements I1 {}
+
+              class M {
+                  m(B a) {}
+              }
+
+              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('superclass of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 extends I1 {}
+
+              class M {
+                  m(B a) {}
+              }
+
+              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('mixin of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class M1 {
+                  m(A a);
+              }
+              abstract class I2 extends Object with M1 {}
+
+              class M {
+                  m(B a) {}
+              }
+
+              class T1 extends Object with /*severe:InvalidMethodOverride*/M
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('interface of abstract superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class Base implements I1 {}
+
+              class M {
+                  m(B a) {}
+              }
+
+              class T1 extends Base with /*severe:InvalidMethodOverride*/M {
+              }
+           '''
+    });
+    testChecker('interface of concrete superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              // See issue #25
+              /*pass should be warning:AnalyzerError*/class Base implements I1 {
+              }
+
+              class M {
+                  m(B a) {}
+              }
+
+              class T1 extends Base with M {
+              }
+           '''
+    });
+  });
+
+  group('superclass override of grand interface', () {
+    testChecker('interface of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 implements I1 {}
+
+              class Base {
+                  m(B a) {}
+              }
+
+              class T1 /*severe:InvalidMethodOverride*/extends Base
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('superclass of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 extends I1 {}
+
+              class Base {
+                  m(B a) {}
+              }
+
+              class T1 /*severe:InvalidMethodOverride*/extends Base
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('mixin of interface of child', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class M1 {
+                  m(A a);
+              }
+              abstract class I2 extends Object with M1 {}
+
+              class Base {
+                  m(B a) {}
+              }
+
+              class T1 /*severe:InvalidMethodOverride*/extends Base
+                  implements I2 {
+              }
+           '''
+    });
+    testChecker('interface of abstract superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              abstract class Base implements I1 {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+
+              class T1 extends Base {
+                  // we consider the base class incomplete because it is
+                  // abstract, so we report the error here too.
+                  // TODO(sigmund): consider tracking overrides in a fine-grain
+                  // manner, then this and the double-overrides would not be
+                  // reported.
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+    testChecker('interface of concrete superclass', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class Base implements I1 {
+                  /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+
+              class T1 extends Base {
+                  m(B a) {}
+              }
+           '''
+    });
+  });
+
+  group('no duplicate reports from overriding interfaces', () {
+    testChecker('type overrides same method in multiple interfaces', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+              abstract class I2 implements I1 {
+                  m(A a);
+              }
+
+              class Base {
+              }
+
+              class T1 implements I2 {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+           '''
+    });
+
+    testChecker('type and base type override same method in interface', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class Base {
+                  m(B a);
+              }
+
+              // Note: no error reported in `extends Base` to avoid duplicating
+              // the error in T1.
+              class T1 extends Base implements I1 {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+
+              // If there is no error in the class, we do report the error at
+              // the base class:
+              class T2 /*severe:InvalidMethodOverride*/extends Base
+                  implements I1 {
+              }
+           '''
+    });
+
+    testChecker('type and mixin override same method in interface', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class M {
+                  m(B a);
+              }
+
+              class T1 extends Object with M implements I1 {
+                /*severe:InvalidMethodOverride*/m(B a) {}
+              }
+
+              class T2 extends Object with /*severe:InvalidMethodOverride*/M
+                  implements I1 {
+              }
+           '''
+    });
+
+    testChecker('two grand types override same method in interface', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class Grandparent {
+                  m(B a) {}
+              }
+
+              class Parent1 extends Grandparent {
+                  m(B a) {}
+              }
+              class Parent2 extends Grandparent {
+              }
+
+              // Note: otherwise both errors would be reported on this line
+              class T1 /*severe:InvalidMethodOverride*/extends Parent1
+                  implements I1 {
+              }
+              class T2 /*severe:InvalidMethodOverride*/extends Parent2
+                  implements I1 {
+              }
+           '''
+    });
+
+    testChecker('two mixins override same method in interface', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class M1 {
+                  m(B a) {}
+              }
+
+              class M2 {
+                  m(B a) {}
+              }
+
+              // Here we want to report both, because the error location is
+              // different.
+              // TODO(sigmund): should we merge these as well?
+              class T1 extends Object
+                  with /*severe:InvalidMethodOverride*/M1
+                  with /*severe:InvalidMethodOverride*/M2
+                  implements I1 {
+              }
+           '''
+    });
+
+    testChecker('base type and mixin override same method in interface', {
+      '/main.dart': '''
+              class A {}
+              class B {}
+
+              abstract class I1 {
+                  m(A a);
+              }
+
+              class Base {
+                  m(B a) {}
+              }
+
+              class M {
+                  m(B a) {}
+              }
+
+              // Here we want to report both, because the error location is
+              // different.
+              // TODO(sigmund): should we merge these as well?
+              class T1 /*severe:InvalidMethodOverride*/extends Base
+                  with /*severe:InvalidMethodOverride*/M
+                  implements I1 {
+              }
+           '''
+    });
+  });
+
+  testChecker('invalid runtime checks', {
+    '/main.dart': '''
+          typedef int I2I(int x);
+          typedef int D2I(x);
+          typedef int II2I(int x, int y);
+          typedef int DI2I(x, int y);
+          typedef int ID2I(int x, y);
+          typedef int DD2I(x, y);
+
+          typedef I2D(int x);
+          typedef D2D(x);
+          typedef II2D(int x, int y);
+          typedef DI2D(x, int y);
+          typedef ID2D(int x, y);
+          typedef DD2D(x, y);
+
+          int foo(int x) => x;
+          int bar(int x, int y) => x + y;
+
+          void main() {
+            bool b;
+            b = /*info:NonGroundTypeCheckInfo*/foo is I2I;
+            b = /*info:NonGroundTypeCheckInfo*/foo is D2I;
+            b = /*info:NonGroundTypeCheckInfo*/foo is I2D;
+            b = foo is D2D;
+
+            b = /*info:NonGroundTypeCheckInfo*/bar is II2I;
+            b = /*info:NonGroundTypeCheckInfo*/bar is DI2I;
+            b = /*info:NonGroundTypeCheckInfo*/bar is ID2I;
+            b = /*info:NonGroundTypeCheckInfo*/bar is II2D;
+            b = /*info:NonGroundTypeCheckInfo*/bar is DD2I;
+            b = /*info:NonGroundTypeCheckInfo*/bar is DI2D;
+            b = /*info:NonGroundTypeCheckInfo*/bar is ID2D;
+            b = bar is DD2D;
+
+            // For as, the validity of checks is deferred to runtime.
+            Function f;
+            f = foo as I2I;
+            f = foo as D2I;
+            f = foo as I2D;
+            f = foo as D2D;
+
+            f = bar as II2I;
+            f = bar as DI2I;
+            f = bar as ID2I;
+            f = bar as II2D;
+            f = bar as DD2I;
+            f = bar as DI2D;
+            f = bar as ID2D;
+            f = bar as DD2D;
+          }
+      '''
+  });
+
+  group('function modifiers', () {
+    testChecker('async', {
+      '/main.dart': '''
+        import 'dart:async';
+        import 'dart:math' show Random;
+
+        dynamic x;
+
+        foo1() async => x;
+        Future foo2() async => x;
+        Future<int> foo3() async => (/*info:DynamicCast*/x);
+        Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x));
+
+        bar1() async { return x; }
+        Future bar2() async { return x; }
+        Future<int> bar3() async { return (/*info:DynamicCast*/x); }
+        Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x)); }
+
+        int y;
+        Future<int> z;
+
+        void baz() async {
+          int a = /*info:DynamicCast*/await x;
+          int b = await y;
+          int c = await z;
+          String d = /*severe:StaticTypeError*/await z;
+        }
+
+        Future<bool> get issue_264 async {
+          await 42;
+          if (new Random().nextBool()) {
+            return true;
+          } else {
+            return /*severe:StaticTypeError*/new Future<bool>.value(false);
+          }
+        }
+    '''
+    });
+
+    testChecker('async*', {
+      '/main.dart': '''
+        import 'dart:async';
+
+        dynamic x;
+
+        bar1() async* { yield x; }
+        Stream bar2() async* { yield x; }
+        Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); }
+        Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<int>()); }
+
+        baz1() async* { yield* (/*info:DynamicCast*/x); }
+        Stream baz2() async* { yield* (/*info:DynamicCast*/x); }
+        Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); }
+        Stream<int> baz4() async* { yield* new Stream<int>(); }
+        Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new Stream()); }
+    '''
+    });
+
+    testChecker('sync*', {
+      '/main.dart': '''
+        import 'dart:async';
+
+        dynamic x;
+
+        bar1() sync* { yield x; }
+        Iterable bar2() sync* { yield x; }
+        Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); }
+        Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterable<int>()); }
+
+        baz1() sync* { yield* (/*info:DynamicCast*/x); }
+        Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); }
+        Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); }
+        Iterable<int> baz4() sync* { yield* new Iterable<int>(); }
+        Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new Iterable()); }
+    '''
+    });
+  });
+}
diff --git a/packages/analyzer/test/src/task/strong/inferred_type_test.dart b/packages/analyzer/test/src/task/strong/inferred_type_test.dart
new file mode 100644
index 0000000..125b356
--- /dev/null
+++ b/packages/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -0,0 +1,1310 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this file needs to be refactored, it's a port from
+// package:dev_compiler's tests
+/// Tests for type inference.
+library test.src.task.strong.inferred_type_test;
+
+import 'package:unittest/unittest.dart';
+
+import 'strong_test_helper.dart';
+
+void main() {
+  // Error also expected when declared type is `int`.
+  testChecker('infer type on var', {
+    '/main.dart': '''
+      test1() {
+        int x = 3;
+        x = /*severe:StaticTypeError*/"hi";
+      }
+    '''
+  });
+
+  // If inferred type is `int`, error is also reported
+  testChecker('infer type on var 2', {
+    '/main.dart': '''
+      test2() {
+        var x = 3;
+        x = /*severe:StaticTypeError*/"hi";
+      }
+    '''
+  });
+
+  testChecker('No error when declared type is `num` and assigned null.', {
+    '/main.dart': '''
+        test1() {
+          num x = 3;
+          x = null;
+        }
+      '''
+  });
+
+  testChecker('do not infer type on dynamic', {
+    '/main.dart': '''
+      test() {
+        dynamic x = 3;
+        x = "hi";
+      }
+    '''
+  });
+
+  testChecker('do not infer type when initializer is null', {
+    '/main.dart': '''
+      test() {
+        var x = null;
+        x = "hi";
+        x = 3;
+      }
+    '''
+  });
+
+  testChecker('infer type on var from field', {
+    '/main.dart': '''
+      class A {
+        int x = 0;
+
+        test1() {
+          var a = x;
+          a = /*severe:StaticTypeError*/"hi";
+          a = 3;
+          var b = y;
+          b = /*severe:StaticTypeError*/"hi";
+          b = 4;
+          var c = z;
+          c = /*severe:StaticTypeError*/"hi";
+          c = 4;
+        }
+
+        int y; // field def after use
+        final z = 42; // should infer `int`
+      }
+    '''
+  });
+
+  testChecker('infer type on var from top-level', {
+    '/main.dart': '''
+      int x = 0;
+
+      test1() {
+        var a = x;
+        a = /*severe:StaticTypeError*/"hi";
+        a = 3;
+        var b = y;
+        b = /*severe:StaticTypeError*/"hi";
+        b = 4;
+        var c = z;
+        c = /*severe:StaticTypeError*/"hi";
+        c = 4;
+      }
+
+      int y = 0; // field def after use
+      final z = 42; // should infer `int`
+    '''
+  });
+
+  testChecker('do not infer field type when initializer is null', {
+    '/main.dart': '''
+      var x = null;
+      var y = 3;
+      class A {
+        static var x = null;
+        static var y = 3;
+
+        var x2 = null;
+        var y2 = 3;
+      }
+
+      test() {
+        x = "hi";
+        y = /*severe:StaticTypeError*/"hi";
+        A.x = "hi";
+        A.y = /*severe:StaticTypeError*/"hi";
+        new A().x2 = "hi";
+        new A().y2 = /*severe:StaticTypeError*/"hi";
+      }
+    '''
+  });
+
+  testChecker('infer from variables in non-cycle imports with flag', {
+    '/a.dart': '''
+          var x = 2;
+      ''',
+    '/main.dart': '''
+          import 'a.dart';
+          var y = x;
+
+          test1() {
+            x = /*severe:StaticTypeError*/"hi";
+            y = /*severe:StaticTypeError*/"hi";
+          }
+    '''
+  });
+
+  testChecker('infer from variables in non-cycle imports with flag 2', {
+    '/a.dart': '''
+          class A { static var x = 2; }
+      ''',
+    '/main.dart': '''
+          import 'a.dart';
+          class B { static var y = A.x; }
+
+          test1() {
+            A.x = /*severe:StaticTypeError*/"hi";
+            B.y = /*severe:StaticTypeError*/"hi";
+          }
+    '''
+  });
+
+  testChecker('infer from variables in cycle libs when flag is on', {
+    '/a.dart': '''
+          import 'main.dart';
+          var x = 2; // ok to infer
+      ''',
+    '/main.dart': '''
+          import 'a.dart';
+          var y = x; // now ok :)
+
+          test1() {
+            int t = 3;
+            t = x;
+            t = y;
+          }
+    '''
+  });
+
+  testChecker('infer from variables in cycle libs when flag is on 2', {
+    '/a.dart': '''
+          import 'main.dart';
+          class A { static var x = 2; }
+      ''',
+    '/main.dart': '''
+          import 'a.dart';
+          class B { static var y = A.x; }
+
+          test1() {
+            int t = 3;
+            t = A.x;
+            t = B.y;
+          }
+    '''
+  });
+
+  testChecker('can infer also from static and instance fields (flag on)', {
+    '/a.dart': '''
+          import 'b.dart';
+          class A {
+            static final a1 = B.b1;
+            final a2 = new B().b2;
+          }
+      ''',
+    '/b.dart': '''
+          class B {
+            static final b1 = 1;
+            final b2 = 1;
+          }
+      ''',
+    '/main.dart': '''
+          import "a.dart";
+
+          test1() {
+            int x = 0;
+            // inference in A now works.
+            x = A.a1;
+            x = new A().a2;
+          }
+    '''
+  });
+
+  testChecker('inference in cycles is deterministic', {
+    '/a.dart': '''
+          import 'b.dart';
+          class A {
+            static final a1 = B.b1;
+            final a2 = new B().b2;
+          }
+      ''',
+    '/b.dart': '''
+          class B {
+            static final b1 = 1;
+            final b2 = 1;
+          }
+      ''',
+    '/c.dart': '''
+          import "main.dart"; // creates a cycle
+
+          class C {
+            static final c1 = 1;
+            final c2 = 1;
+          }
+      ''',
+    '/e.dart': '''
+          import 'a.dart';
+          part 'e2.dart';
+
+          class E {
+            static final e1 = 1;
+            static final e2 = F.f1;
+            static final e3 = A.a1;
+            final e4 = 1;
+            final e5 = new F().f2;
+            final e6 = new A().a2;
+          }
+      ''',
+    '/f.dart': '''
+          part 'f2.dart';
+      ''',
+    '/e2.dart': '''
+          class F {
+            static final f1 = 1;
+            final f2 = 1;
+          }
+      ''',
+    '/main.dart': '''
+          import "a.dart";
+          import "c.dart";
+          import "e.dart";
+
+          class D {
+            static final d1 = A.a1 + 1;
+            static final d2 = C.c1 + 1;
+            final d3 = new A().a2;
+            final d4 = new C().c2;
+          }
+
+          test1() {
+            int x = 0;
+            // inference in A works, it's not in a cycle
+            x = A.a1;
+            x = new A().a2;
+
+            // Within a cycle we allow inference when the RHS is well known, but
+            // not when it depends on other fields within the cycle
+            x = C.c1;
+            x = D.d1;
+            x = D.d2;
+            x = new C().c2;
+            x = new D().d3;
+            x = /*info:DynamicCast*/new D().d4;
+
+
+            // Similarly if the library contains parts.
+            x = E.e1;
+            x = E.e2;
+            x = E.e3;
+            x = new E().e4;
+            x = /*info:DynamicCast*/new E().e5;
+            x = new E().e6;
+            x = F.f1;
+            x = new F().f2;
+          }
+    '''
+  });
+
+  testChecker(
+      'infer from complex expressions if the outer-most value is precise', {
+    '/main.dart': '''
+        class A { int x; B operator+(other) {} }
+        class B extends A { B(ignore); }
+        var a = new A();
+        // Note: it doesn't matter that some of these refer to 'x'.
+        var b = new B(x);       // allocations
+        var c1 = [x];           // list literals
+        var c2 = const [];
+        var d = {'a': 'b'};     // map literals
+        var e = new A()..x = 3; // cascades
+        var f = 2 + 3;          // binary expressions are OK if the left operand
+                                // is from a library in a different strongest
+                                // conected component.
+        var g = -3;
+        var h = new A() + 3;
+        var i = - new A();
+        var j = null as B;
+
+        test1() {
+          a = /*severe:StaticTypeError*/"hi";
+          a = new B(3);
+          b = /*severe:StaticTypeError*/"hi";
+          b = new B(3);
+          c1 = [];
+          c1 = /*severe:StaticTypeError*/{};
+          c2 = [];
+          c2 = /*severe:StaticTypeError*/{};
+          d = {};
+          d = /*severe:StaticTypeError*/3;
+          e = new A();
+          e = /*severe:StaticTypeError*/{};
+          f = 3;
+          f = /*severe:StaticTypeError*/false;
+          g = 1;
+          g = /*severe:StaticTypeError*/false;
+          h = /*severe:StaticTypeError*/false;
+          h = new B();
+          i = false;
+          j = new B();
+          j = /*severe:StaticTypeError*/false;
+          j = /*severe:StaticTypeError*/[];
+        }
+    '''
+  });
+
+  // but flags can enable this behavior.
+  testChecker('infer if complex expressions read possibly inferred field', {
+    '/a.dart': '''
+        class A {
+          var x = 3;
+        }
+      ''',
+    '/main.dart': '''
+        import 'a.dart';
+        class B {
+          var y = 3;
+        }
+        final t1 = new A();
+        final t2 = new A().x;
+        final t3 = new B();
+        final t4 = new B().y;
+
+        test1() {
+          int i = 0;
+          A a;
+          B b;
+          a = t1;
+          i = t2;
+          b = t3;
+          i = /*info:DynamicCast*/t4;
+          i = new B().y; // B.y was inferred though
+        }
+    '''
+  });
+
+  group('infer types on loop indices', () {
+    testChecker('foreach loop', {
+      '/main.dart': '''
+      class Foo {
+        int bar = 42;
+      }
+
+      class Bar<T extends Iterable<String>> {
+        void foo(T t) {
+          for (var i in t) {
+            int x = /*severe:StaticTypeError*/i;
+          }
+        }
+      }
+
+      class Baz<T, E extends Iterable<T>, S extends E> {
+        void foo(S t) {
+          for (var i in t) {
+            int x = /*severe:StaticTypeError*/i;
+            T y = i;
+          }
+        }
+      }
+
+      test() {
+        var list = <Foo>[];
+        for (var x in list) {
+          String y = /*severe:StaticTypeError*/x;
+        }
+
+        for (dynamic x in list) {
+          String y = /*info:DynamicCast*/x;
+        }
+
+        for (String x in /*severe:StaticTypeError*/list) {
+          String y = x;
+        }
+
+        var z;
+        for(z in list) {
+          String y = /*info:DynamicCast*/z;
+        }
+
+        Iterable iter = list;
+        for (Foo x in /*warning:DownCastComposite*/iter) {
+          var y = x;
+        }
+
+        dynamic iter2 = list;
+        for (Foo x in /*warning:DownCastComposite*/iter2) {
+          var y = x;
+        }
+
+        var map = <String, Foo>{};
+        // Error: map must be an Iterable.
+        for (var x in /*severe:StaticTypeError*/map) {
+          String y = /*info:DynamicCast*/x;
+        }
+
+        // We're not properly inferring that map.keys is an Iterable<String>
+        // and that x is a String.
+        for (var x in map.keys) {
+          String y = x;
+        }
+      }
+      '''
+    });
+
+    testChecker('for loop, with inference', {
+      '/main.dart': '''
+      test() {
+        for (var i = 0; i < 10; i++) {
+          int j = i + 1;
+        }
+      }
+      '''
+    });
+  });
+
+  testChecker('propagate inference to field in class', {
+    '/main.dart': '''
+      class A {
+        int x = 2;
+      }
+
+      test() {
+        var a = new A();
+        A b = a;                      // doesn't require down cast
+        print(a.x);     // doesn't require dynamic invoke
+        print(a.x + 2); // ok to use in bigger expression
+      }
+    '''
+  });
+
+  testChecker('propagate inference to field in class dynamic warnings', {
+    '/main.dart': '''
+      class A {
+        int x = 2;
+      }
+
+      test() {
+        dynamic a = new A();
+        A b = /*info:DynamicCast*/a;
+        print(/*info:DynamicInvoke*/a.x);
+        print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2);
+      }
+    '''
+  });
+
+  testChecker('propagate inference transitively', {
+    '/main.dart': '''
+      class A {
+        int x = 2;
+      }
+
+      test5() {
+        var a1 = new A();
+        a1.x = /*severe:StaticTypeError*/"hi";
+
+        A a2 = new A();
+        a2.x = /*severe:StaticTypeError*/"hi";
+      }
+    '''
+  });
+
+  testChecker('propagate inference transitively 2', {
+    '/main.dart': '''
+      class A {
+        int x = 42;
+      }
+
+      class B {
+        A a = new A();
+      }
+
+      class C {
+        B b = new B();
+      }
+
+      class D {
+        C c = new C();
+      }
+
+      void main() {
+        var d1 = new D();
+        print(d1.c.b.a.x);
+
+        D d2 = new D();
+        print(d2.c.b.a.x);
+      }
+    '''
+  });
+
+  group('infer type on overridden fields', () {
+    testChecker('2', {
+      '/main.dart': '''
+        class A {
+          int x = 2;
+        }
+
+        class B extends A {
+          get x => 3;
+        }
+
+        foo() {
+          String y = /*severe:StaticTypeError*/new B().x;
+          int z = new B().x;
+        }
+    '''
+    });
+
+    testChecker('4', {
+      '/main.dart': '''
+        class A {
+          int x = 2;
+        }
+
+        class B implements A {
+          get x => 3;
+        }
+
+        foo() {
+          String y = /*severe:StaticTypeError*/new B().x;
+          int z = new B().x;
+        }
+    '''
+    });
+  });
+
+  group('infer types on generic instantiations', () {
+    testChecker('infer', {
+      '/main.dart': '''
+        class A<T> {
+          T x;
+        }
+
+        class B implements A<int> {
+          /*severe:InvalidMethodOverride*/dynamic get x => 3;
+        }
+
+        foo() {
+          String y = /*info:DynamicCast*/new B().x;
+          int z = /*info:DynamicCast*/new B().x;
+        }
+    '''
+    });
+
+    testChecker('3', {
+      '/main.dart': '''
+        class A<T> {
+          T x;
+          T w;
+        }
+
+        class B implements A<int> {
+          get x => 3;
+          get w => /*severe:StaticTypeError*/"hello";
+        }
+
+        foo() {
+          String y = /*severe:StaticTypeError*/new B().x;
+          int z = new B().x;
+        }
+    '''
+    });
+
+    testChecker('4', {
+      '/main.dart': '''
+        class A<T> {
+          T x;
+        }
+
+        class B<E> extends A<E> {
+          E y;
+          get x => y;
+        }
+
+        foo() {
+          int y = /*severe:StaticTypeError*/new B<String>().x;
+          String z = new B<String>().x;
+        }
+    '''
+    });
+
+    testChecker('5', {
+      '/main.dart': '''
+        abstract class I<E> {
+          String m(a, String f(v, T e));
+        }
+
+        abstract class A<E> implements I<E> {
+          const A();
+          String m(a, String f(v, T e));
+        }
+
+        abstract class M {
+          int y;
+        }
+
+        class B<E> extends A<E> implements M {
+          const B();
+          int get y => 0;
+
+          m(a, f(v, T e)) {}
+        }
+
+        foo () {
+          int y = /*severe:StaticTypeError*/new B().m(null, null);
+          String z = new B().m(null, null);
+        }
+    '''
+    });
+  });
+
+  testChecker('infer type regardless of declaration order or cycles', {
+    '/b.dart': '''
+        import 'main.dart';
+
+        class B extends A { }
+      ''',
+    '/main.dart': '''
+        import 'b.dart';
+        class C extends B {
+          get x;
+        }
+        class A {
+          int get x;
+        }
+        foo () {
+          int y = new C().x;
+          String y = /*severe:StaticTypeError*/new C().x;
+        }
+    '''
+  });
+
+  // Note: this is a regression test for a non-deterministic behavior we used to
+  // have with inference in library cycles. If you see this test flake out,
+  // change `test` to `skip_test` and reopen bug #48.
+  testChecker('infer types on generic instantiations in library cycle', {
+    '/a.dart': '''
+          import 'main.dart';
+        abstract class I<E> {
+          A<E> m(a, String f(v, int e));
+        }
+      ''',
+    '/main.dart': '''
+          import 'a.dart';
+
+        abstract class A<E> implements I<E> {
+          const A();
+
+          E value;
+        }
+
+        abstract class M {
+          int y;
+        }
+
+        class B<E> extends A<E> implements M {
+          const B();
+          int get y => 0;
+
+          m(a, f(v, int e)) {}
+        }
+
+        foo () {
+          int y = /*severe:StaticTypeError*/new B<String>().m(null, null).value;
+          String z = new B<String>().m(null, null).value;
+        }
+    '''
+  });
+
+  group('do not infer overridden fields that explicitly say dynamic', () {
+    testChecker('infer', {
+      '/main.dart': '''
+          class A {
+            int x = 2;
+          }
+
+          class B implements A {
+            /*severe:InvalidMethodOverride*/dynamic get x => 3;
+          }
+
+          foo() {
+            String y = /*info:DynamicCast*/new B().x;
+            int z = /*info:DynamicCast*/new B().x;
+          }
+      '''
+    });
+  });
+
+  testChecker('conflicts can happen', {
+    '/main.dart': '''
+        class I1 {
+          int x;
+        }
+        class I2 extends I1 {
+          int y;
+        }
+
+        class A {
+          final I1 a;
+        }
+
+        class B {
+          final I2 a;
+        }
+
+        class C1 extends A implements B {
+          /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null;
+        }
+
+        // Still ambiguous
+        class C2 extends B implements A {
+          /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null;
+        }
+    '''
+  });
+
+  testChecker('conflicts can happen 2', {
+    '/main.dart': '''
+        class I1 {
+          int x;
+        }
+        class I2 {
+          int y;
+        }
+
+        class I3 implements I1, I2 {
+          int x;
+          int y;
+        }
+
+        class A {
+          final I1 a;
+        }
+
+        class B {
+          final I2 a;
+        }
+
+        class C1 extends A implements B {
+          I3 get a => null;
+        }
+
+        class C2 extends A implements B {
+          /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a => null;
+        }
+    '''
+  });
+
+  testChecker(
+      'infer from RHS only if it wont conflict with overridden fields', {
+    '/main.dart': '''
+        class A {
+          var x;
+        }
+
+        class B extends A {
+          var x = 2;
+        }
+
+        foo() {
+          String y = /*info:DynamicCast*/new B().x;
+          int z = /*info:DynamicCast*/new B().x;
+        }
+    '''
+  });
+
+  testChecker(
+      'infer from RHS only if it wont conflict with overridden fields 2', {
+    '/main.dart': '''
+        class A {
+          final x;
+        }
+
+        class B extends A {
+          final x = 2;
+        }
+
+        foo() {
+          String y = /*severe:StaticTypeError*/new B().x;
+          int z = new B().x;
+        }
+    '''
+  });
+
+  testChecker('infer correctly on multiple variables declared together', {
+    '/main.dart': '''
+        class A {
+          var x, y = 2, z = "hi";
+        }
+
+        class B extends A {
+          var x = 2, y = 3, z, w = 2;
+        }
+
+        foo() {
+          String s;
+          int i;
+
+          s = /*info:DynamicCast*/new B().x;
+          s = /*severe:StaticTypeError*/new B().y;
+          s = new B().z;
+          s = /*severe:StaticTypeError*/new B().w;
+
+          i = /*info:DynamicCast*/new B().x;
+          i = new B().y;
+          i = /*severe:StaticTypeError*/new B().z;
+          i = new B().w;
+        }
+    '''
+  });
+
+  testChecker('infer consts transitively', {
+    '/b.dart': '''
+        const b1 = 2;
+      ''',
+    '/a.dart': '''
+        import 'main.dart';
+        import 'b.dart';
+        const a1 = m2;
+        const a2 = b1;
+      ''',
+    '/main.dart': '''
+        import 'a.dart';
+        const m1 = a1;
+        const m2 = a2;
+
+        foo() {
+          int i;
+          i = m1;
+        }
+    '''
+  });
+
+  testChecker('infer statics transitively', {
+    '/b.dart': '''
+        final b1 = 2;
+      ''',
+    '/a.dart': '''
+        import 'main.dart';
+        import 'b.dart';
+        final a1 = m2;
+        class A {
+          static final a2 = b1;
+        }
+      ''',
+    '/main.dart': '''
+        import 'a.dart';
+        final m1 = a1;
+        final m2 = A.a2;
+
+        foo() {
+          int i;
+          i = m1;
+        }
+    '''
+  });
+
+  testChecker('infer statics transitively 2', {
+    '/main.dart': '''
+        const x1 = 1;
+        final x2 = 1;
+        final y1 = x1;
+        final y2 = x2;
+
+        foo() {
+          int i;
+          i = y1;
+          i = y2;
+        }
+    '''
+  });
+
+  testChecker('infer statics transitively 3', {
+    '/a.dart': '''
+        const a1 = 3;
+        const a2 = 4;
+        class A {
+          a3;
+        }
+      ''',
+    '/main.dart': '''
+        import 'a.dart' show a1, A;
+        import 'a.dart' as p show a2, A;
+        const t1 = 1;
+        const t2 = t1;
+        const t3 = a1;
+        const t4 = p.a2;
+        const t5 = A.a3;
+        const t6 = p.A.a3;
+
+        foo() {
+          int i;
+          i = t1;
+          i = t2;
+          i = t3;
+          i = t4;
+        }
+    '''
+  });
+
+  testChecker('infer statics with method invocations', {
+    '/a.dart': '''
+        m3(String a, String b, [a1,a2]) {}
+      ''',
+    '/main.dart': '''
+        import 'a.dart';
+        class T {
+          static final T foo = m1(m2(m3('', '')));
+          static T m1(String m) { return null; }
+          static String m2(e) { return ''; }
+        }
+
+
+    '''
+  });
+
+  testChecker('downwards inference: miscellaneous', {
+    '/main.dart': '''
+      typedef (T x);
+      class A<T> {
+        Function2<T> x;
+        A(this.x);
+      }
+      void main() {
+          {  // Variables, nested literals
+            var x = "hello";
+            var y = 3;
+            void f(List<Map<int, String>> l) {};
+            f(/*info:InferredTypeLiteral*/[{y: x}]);
+          }
+          {
+            int f(int x) {};
+            A<int> a = /*info:InferredTypeAllocation*/new A(f);
+          }
+      }
+      '''
+  });
+
+  group('downwards inference on instance creations', () {
+    String info = 'info:InferredTypeAllocation';
+    String code = '''
+      class A<S, T> {
+        S x;
+        T y;
+        A(this.x, this.y);
+        A.named(this.x, this.y);
+      }
+
+      class B<S, T> extends A<T, S> {
+        B(S y, T x) : super(x, y);
+        B.named(S y, T x) : super.named(x, y);
+      }
+
+      class C<S> extends B<S, S> {
+        C(S a) : super(a, a);
+        C.named(S a) : super.named(a, a);
+      }
+
+      class D<S, T> extends B<T, int> {
+        D(T a) : super(a, 3);
+        D.named(T a) : super.named(a, 3);
+      }
+
+      class E<S, T> extends A<C<S>, T> {
+        E(T a) : super(null, a);
+      }
+
+      class F<S, T> extends A<S, T> {
+        F(S x, T y, {List<S> a, List<T> b}) : super(x, y);
+        F.named(S x, T y, [S a, T b]) : super(a, b);
+      }
+
+      void main() {
+        {
+          A<int, String> a0 = /*$info*/new A(3, "hello");
+          A<int, String> a1 = /*$info*/new A.named(3, "hello");
+          A<int, String> a2 = new A<int, String>(3, "hello");
+          A<int, String> a3 = new A<int, String>.named(3, "hello");
+          A<int, String> a4 = /*severe:StaticTypeError*/new A<int, dynamic>(3, "hello");
+          A<int, String> a5 = /*severe:StaticTypeError*/new A<dynamic, dynamic>.named(3, "hello");
+        }
+        {
+          A<int, String> a0 = /*severe:StaticTypeError*/new A("hello", 3);
+          A<int, String> a1 = /*severe:StaticTypeError*/new A.named("hello", 3);
+        }
+        {
+          A<int, String> a0 = /*$info*/new B("hello", 3);
+          A<int, String> a1 = /*$info*/new B.named("hello", 3);
+          A<int, String> a2 = new B<String, int>("hello", 3);
+          A<int, String> a3 = new B<String, int>.named("hello", 3);
+          A<int, String> a4 = /*severe:StaticTypeError*/new B<String, dynamic>("hello", 3);
+          A<int, String> a5 = /*severe:StaticTypeError*/new B<dynamic, dynamic>.named("hello", 3);
+        }
+        {
+          A<int, String> a0 = /*severe:StaticTypeError*/new B(3, "hello");
+          A<int, String> a1 = /*severe:StaticTypeError*/new B.named(3, "hello");
+        }
+        {
+          A<int, int> a0 = /*$info*/new C(3);
+          A<int, int> a1 = /*$info*/new C.named(3);
+          A<int, int> a2 = new C<int>(3);
+          A<int, int> a3 = new C<int>.named(3);
+          A<int, int> a4 = /*severe:StaticTypeError*/new C<dynamic>(3);
+          A<int, int> a5 = /*severe:StaticTypeError*/new C<dynamic>.named(3);
+        }
+        {
+          A<int, int> a0 = /*severe:StaticTypeError*/new C("hello");
+          A<int, int> a1 = /*severe:StaticTypeError*/new C.named("hello");
+        }
+        {
+          A<int, String> a0 = /*$info*/new D("hello");
+          A<int, String> a1 = /*$info*/new D.named("hello");
+          A<int, String> a2 = new D<int, String>("hello");
+          A<int, String> a3 = new D<String, String>.named("hello");
+          A<int, String> a4 = /*severe:StaticTypeError*/new D<num, dynamic>("hello");
+          A<int, String> a5 = /*severe:StaticTypeError*/new D<dynamic, dynamic>.named("hello");
+        }
+        {
+          A<int, String> a0 = /*severe:StaticTypeError*/new D(3);
+          A<int, String> a1 = /*severe:StaticTypeError*/new D.named(3);
+        }
+        { // Currently we only allow variable constraints.  Test that we reject.
+          A<C<int>, String> a0 = /*severe:StaticTypeError*/new E("hello");
+        }
+        { // Check named and optional arguments
+          A<int, String> a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]);
+          A<int, String> a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["hello"], b:[3]);
+          A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello");
+          A<int, String> a3 = /*$info*/new F.named(3, "hello");
+          A<int, String> a4 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello", 3);
+          A<int, String> a5 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello");
+        }
+      }
+        ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  group('downwards inference on list literals', () {
+    String info = "info:InferredTypeLiteral";
+    String code = '''
+      void foo([List<String> list1 = /*$info*/const [],
+                List<String> list2 = /*severe:StaticTypeError*/const [42]]) {
+      }
+
+      void main() {
+        {
+          List<int> l0 = /*$info*/[];
+          List<int> l1 = /*$info*/[3];
+          List<int> l2 = /*severe:StaticTypeError*/["hello"];
+          List<int> l3 = /*severe:StaticTypeError*/["hello", 3];
+        }
+        {
+          List<dynamic> l0 = [];
+          List<dynamic> l1 = [3];
+          List<dynamic> l2 = ["hello"];
+          List<dynamic> l3 = ["hello", 3];
+        }
+        {
+          List<int> l0 = /*severe:StaticTypeError*/<num>[];
+          List<int> l1 = /*severe:StaticTypeError*/<num>[3];
+          List<int> l2 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello"];
+          List<int> l3 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello", 3];
+        }
+        {
+          Iterable<int> i0 = /*$info*/[];
+          Iterable<int> i1 = /*$info*/[3];
+          Iterable<int> i2 = /*severe:StaticTypeError*/["hello"];
+          Iterable<int> i3 = /*severe:StaticTypeError*/["hello", 3];
+        }
+        {
+          const List<int> c0 = /*$info*/const [];
+          const List<int> c1 = /*$info*/const [3];
+          const List<int> c2 = /*severe:StaticTypeError*/const ["hello"];
+          const List<int> c3 = /*severe:StaticTypeError*/const ["hello", 3];
+        }
+      }
+      ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  group('downwards inference on function arguments', () {
+    String info = "info:InferredTypeLiteral";
+    String code = '''
+      void f0(List<int> a) {};
+      void f1({List<int> a}) {};
+      void f2(Iterable<int> a) {};
+      void f3(Iterable<Iterable<int>> a) {};
+      void f4({Iterable<Iterable<int>> a}) {};
+      void main() {
+        f0(/*$info*/[]);
+        f0(/*$info*/[3]);
+        f0(/*severe:StaticTypeError*/["hello"]);
+        f0(/*severe:StaticTypeError*/["hello", 3]);
+
+        f1(a: /*$info*/[]);
+        f1(a: /*$info*/[3]);
+        f1(a: /*severe:StaticTypeError*/["hello"]);
+        f1(a: /*severe:StaticTypeError*/["hello", 3]);
+
+        f2(/*$info*/[]);
+        f2(/*$info*/[3]);
+        f2(/*severe:StaticTypeError*/["hello"]);
+        f2(/*severe:StaticTypeError*/["hello", 3]);
+
+        f3(/*$info*/[]);
+        f3(/*$info*/[[3]]);
+        f3(/*severe:StaticTypeError*/[["hello"]]);
+        f3(/*severe:StaticTypeError*/[["hello"], [3]]);
+
+        f4(a: /*$info*/[]);
+        f4(a: /*$info*/[[3]]);
+        f4(a: /*severe:StaticTypeError*/[["hello"]]);
+        f4(a: /*severe:StaticTypeError*/[["hello"], [3]]);
+      }
+      ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  group('downwards inference on map literals', () {
+    String info = "info:InferredTypeLiteral";
+    String code = '''
+      void foo([Map<int, String> m1 = /*$info*/const {1: "hello"},
+                Map<int, String> m1 = /*severe:StaticTypeError*/const {"hello": "world"}]) {
+      }
+      void main() {
+        {
+          Map<int, String> l0 = /*$info*/{};
+          Map<int, String> l1 = /*$info*/{3: "hello"};
+          Map<int, String> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
+          Map<int, String> l3 = /*severe:StaticTypeError*/{3: 3};
+          Map<int, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+        }
+        {
+          Map<dynamic, dynamic> l0 = {};
+          Map<dynamic, dynamic> l1 = {3: "hello"};
+          Map<dynamic, dynamic> l2 = {"hello": "hello"};
+          Map<dynamic, dynamic> l3 = {3: 3};
+          Map<dynamic, dynamic> l4 = {3:"hello", "hello": 3};
+        }
+        {
+          Map<dynamic, String> l0 = /*$info*/{};
+          Map<dynamic, String> l1 = /*$info*/{3: "hello"};
+          Map<dynamic, String> l2 = /*$info*/{"hello": "hello"};
+          Map<dynamic, String> l3 = /*severe:StaticTypeError*/{3: 3};
+          Map<dynamic, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+        }
+        {
+          Map<int, dynamic> l0 = /*$info*/{};
+          Map<int, dynamic> l1 = /*$info*/{3: "hello"};
+          Map<int, dynamic> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
+          Map<int, dynamic> l3 = /*$info*/{3: 3};
+          Map<int, dynamic> l3 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+        }
+        {
+          Map<int, String> l0 = /*severe:StaticTypeError*/<num, dynamic>{};
+          Map<int, String> l1 = /*severe:StaticTypeError*/<num, dynamic>{3: "hello"};
+          Map<int, String> l3 = /*severe:StaticTypeError*/<num, dynamic>{3: 3};
+        }
+        {
+          const Map<int, String> l0 = /*$info*/const {};
+          const Map<int, String> l1 = /*$info*/const {3: "hello"};
+          const Map<int, String> l2 = /*severe:StaticTypeError*/const {"hello": "hello"};
+          const Map<int, String> l3 = /*severe:StaticTypeError*/const {3: 3};
+          const Map<int, String> l4 = /*severe:StaticTypeError*/const {3:"hello", "hello": 3};
+        }
+      }
+      ''';
+    testChecker('infer downwards', {'/main.dart': code});
+  });
+
+  testChecker('downwards inference on function expressions', {
+    '/main.dart': '''
+      typedef T Function2<S, T>(S x);
+
+      void main () {
+        {
+          Function2<int, String> l0 = (int x) => null;
+          Function2<int, String> l1 = (int x) => "hello";
+          Function2<int, String> l2 = /*severe:StaticTypeError*/(String x) => "hello";
+          Function2<int, String> l3 = /*severe:StaticTypeError*/(int x) => 3;
+          Function2<int, String> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return 3};
+        }
+        {
+          Function2<int, String> l0 = /*info:InferredTypeClosure*/(x) => null;
+          Function2<int, String> l1 = /*info:InferredTypeClosure*/(x) => "hello";
+          Function2<int, String> l2 = /*severe:StaticTypeError*/(x) => 3;
+          Function2<int, String> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(x) {return 3};
+        }
+        {
+          Function2<int, List<String>> l0 = (int x) => null;
+          Function2<int, List<String>> l1 = /*info:InferredTypeClosure*/(int x) => ["hello"];
+          Function2<int, List<String>> l2 = /*severe:StaticTypeError*/(String x) => ["hello"];
+          Function2<int, List<String>> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) => [3];
+          Function2<int, List<String>> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return [3]};
+        }
+        {
+          Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x;
+          Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1;
+          Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x;
+          Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
+          Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
+        }
+      }
+      '''
+  });
+
+  testChecker('inferred initializing formal checks default value', {
+    '/main.dart': '''
+      class Foo {
+        var x = 1;
+        Foo([this.x = /*severe:StaticTypeError*/"1"]);
+      }'''
+  });
+
+  group('quasi-generics', () {
+    testChecker('dart:math min/max', {
+      '/main.dart': '''
+        import 'dart:math';
+
+        void printInt(int x) => print(x);
+        void printDouble(double x) => print(x);
+
+        num myMax(num x, num y) => max(x, y);
+
+        main() {
+          // Okay if static types match.
+          printInt(max(1, 2));
+          printInt(min(1, 2));
+          printDouble(max(1.0, 2.0));
+          printDouble(min(1.0, 2.0));
+
+          // No help for user-defined functions from num->num->num.
+          printInt(/*info:DownCastImplicit*/myMax(1, 2));
+          printInt(myMax(1, 2) as int);
+
+          // Mixing int and double means return type is num.
+          printInt(/*info:DownCastImplicit*/max(1, 2.0));
+          printInt(/*info:DownCastImplicit*/min(1, 2.0));
+          printDouble(/*info:DownCastImplicit*/max(1, 2.0));
+          printDouble(/*info:DownCastImplicit*/min(1, 2.0));
+
+          // Types other than int and double are not accepted.
+          printInt(
+              /*info:DownCastImplicit*/min(
+                  /*severe:StaticTypeError*/"hi",
+                  /*severe:StaticTypeError*/"there"));
+        }
+    '''
+    });
+
+    testChecker('Iterable and Future', {
+      '/main.dart': '''
+        import 'dart:async';
+
+        Future<int> make(int x) => (/*info:InferredTypeAllocation*/new Future(() => x));
+
+        main() {
+          Iterable<Future<int>> list = <int>[1, 2, 3].map(make);
+          Future<List<int>> results = Future.wait(list);
+          Future<String> results2 = results.then((List<int> list) 
+            => list.fold('', (String x, int y) => x + y.toString()));
+        }
+    '''
+    });
+  });
+}
diff --git a/packages/analyzer/test/src/task/strong/strong_test_helper.dart b/packages/analyzer/test/src/task/strong/strong_test_helper.dart
new file mode 100644
index 0000000..330801f
--- /dev/null
+++ b/packages/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -0,0 +1,500 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this file needs to be refactored, it's a port from
+// package:dev_compiler's tests
+library test.src.task.strong.strong_test_helper;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/context/context.dart' show SdkAnalysisContext;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart' hide SdkAnalysisContext;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:analyzer/src/task/strong/rules.dart';
+import 'package:logging/logging.dart'; // TODO(jmesserly): remove
+import 'package:source_span/source_span.dart'; // TODO(jmesserly): remove
+import 'package:unittest/unittest.dart';
+
+/// Run the checker on a program with files contents as indicated in
+/// [testFiles].
+///
+/// This function makes several assumptions to make it easier to describe error
+/// expectations:
+///
+///   * a file named `/main.dart` exists in [testFiles].
+///   * all expected failures are listed in the source code using comments
+///   immediately in front of the AST node that should contain the error.
+///   * errors are formatted as a token `level:Type`, where `level` is the
+///   logging level were the error would be reported at, and `Type` is the
+///   concrete subclass of [StaticInfo] that denotes the error.
+///
+/// For example, to check that an assignment produces a warning about a boxing
+/// conversion, you can describe the test as follows:
+///
+///     testChecker({
+///       '/main.dart': '''
+///           testMethod() {
+///             dynamic x = /*warning:Box*/3;
+///           }
+///       '''
+///     });
+///
+void testChecker(String name, Map<String, String> testFiles) {
+  test(name, () {
+    expect(testFiles.containsKey('/main.dart'), isTrue,
+        reason: '`/main.dart` is missing in testFiles');
+
+    var provider = new MemoryResourceProvider();
+    testFiles.forEach((key, value) {
+      var scheme = 'package:';
+      if (key.startsWith(scheme)) {
+        key = '/packages/${key.substring(scheme.length)}';
+      }
+      provider.newFile(key, value);
+    });
+    var uriResolver = new TestUriResolver(provider);
+    // Enable task model strong mode
+    AnalysisEngine.instance.useTaskModel = true;
+    var context = AnalysisEngine.instance.createAnalysisContext();
+    context.analysisOptions.strongMode = true;
+
+    context.sourceFactory = new SourceFactory([
+      new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
+      uriResolver
+    ]);
+
+    // Run the checker on /main.dart.
+    Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
+    var initialLibrary =
+        context.resolveCompilationUnit2(mainSource, mainSource);
+
+    var collector = new _ErrorCollector();
+    var checker = new CodeChecker(
+        new TypeRules(context.typeProvider), collector,
+        hints: true);
+
+    // Extract expectations from the comments in the test files, and
+    // check that all errors we emit are included in the expected map.
+    var allLibraries = reachableLibraries(initialLibrary.element.library);
+    for (var lib in allLibraries) {
+      for (var unit in lib.units) {
+        var errors = <AnalysisError>[];
+        collector.errors = errors;
+
+        var source = unit.source;
+        if (source.uri.scheme == 'dart') continue;
+
+        var librarySource = context.getLibrariesContaining(source).single;
+        var resolved = context.resolveCompilationUnit2(source, librarySource);
+        checker.visitCompilationUnit(resolved);
+
+        new _ExpectedErrorVisitor(errors).validate(resolved);
+      }
+    }
+  });
+}
+
+class _ErrorCollector implements AnalysisErrorListener {
+  List<AnalysisError> errors;
+  final bool hints;
+  _ErrorCollector({this.hints: true});
+
+  void onError(AnalysisError error) {
+    // Unless DDC hints are requested, filter them out.
+    var HINT = ErrorSeverity.INFO.ordinal;
+    if (hints || error.errorCode.errorSeverity.ordinal > HINT) {
+      errors.add(error);
+    }
+  }
+}
+
+class TestUriResolver extends ResourceUriResolver {
+  final MemoryResourceProvider provider;
+  TestUriResolver(provider)
+      : provider = provider,
+        super(provider);
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    if (uri.scheme == 'package') {
+      return (provider.getResource('/packages/' + uri.path) as File)
+          .createSource(uri);
+    }
+    return super.resolveAbsolute(uri, actualUri);
+  }
+}
+
+class _ExpectedErrorVisitor extends UnifyingAstVisitor {
+  final Set<AnalysisError> _actualErrors;
+  CompilationUnit _unit;
+  String _unitSourceCode;
+
+  _ExpectedErrorVisitor(List<AnalysisError> actualErrors)
+      : _actualErrors = new Set.from(actualErrors);
+
+  validate(CompilationUnit unit) {
+    _unit = unit;
+    // This reads the file. Only safe because tests use MemoryFileSystem.
+    _unitSourceCode = unit.element.source.contents.data;
+
+    // Visit the compilation unit.
+    unit.accept(this);
+
+    if (_actualErrors.isNotEmpty) {
+      var actualMsgs = _actualErrors.map(_formatActualError).join('\n');
+      fail('Unexpected errors reported by checker:\n\n$actualMsgs');
+    }
+  }
+
+  visitNode(AstNode node) {
+    var token = node.beginToken;
+    var comment = token.precedingComments;
+    // Use error marker found in an immediately preceding comment,
+    // and attach it to the outermost expression that starts at that token.
+    if (comment != null) {
+      while (comment.next != null) {
+        comment = comment.next;
+      }
+      if (comment.end == token.offset && node.parent.beginToken != token) {
+        var commentText = '$comment';
+        var start = commentText.lastIndexOf('/*');
+        var end = commentText.lastIndexOf('*/');
+        if (start != -1 && end != -1) {
+          expect(start, lessThan(end));
+          var errors = commentText.substring(start + 2, end).split(',');
+          var expectations =
+              errors.map(_ErrorExpectation.parse).where((x) => x != null);
+
+          for (var e in expectations) _expectError(node, e);
+        }
+      }
+    }
+    return super.visitNode(node);
+  }
+
+  void _expectError(AstNode node, _ErrorExpectation expected) {
+    // See if we can find the expected error in our actual errors
+    for (var actual in _actualErrors) {
+      if (actual.offset == node.offset && actual.length == node.length) {
+        var actualMsg = _formatActualError(actual);
+        expect(_actualErrorLevel(actual), expected.level,
+            reason: 'expected different error code at:\n\n$actualMsg');
+        expect(errorCodeName(actual.errorCode), expected.typeName,
+            reason: 'expected different error type at:\n\n$actualMsg');
+
+        // We found it. Stop the search.
+        _actualErrors.remove(actual);
+        return;
+      }
+    }
+
+    var span = _createSpan(node.offset, node.length);
+    var levelName = expected.level.name.toLowerCase();
+    var msg = span.message(expected.typeName, color: colorOf(levelName));
+    fail('expected error was not reported at:\n\n$levelName: $msg');
+  }
+
+  Level _actualErrorLevel(AnalysisError actual) {
+    return const <ErrorSeverity, Level>{
+      ErrorSeverity.ERROR: Level.SEVERE,
+      ErrorSeverity.WARNING: Level.WARNING,
+      ErrorSeverity.INFO: Level.INFO
+    }[actual.errorCode.errorSeverity];
+  }
+
+  String _formatActualError(AnalysisError actual) {
+    var span = _createSpan(actual.offset, actual.length);
+    var levelName = _actualErrorLevel(actual).name.toLowerCase();
+    var msg = span.message(actual.message, color: colorOf(levelName));
+    return '$levelName: [${errorCodeName(actual.errorCode)}] $msg';
+  }
+
+  SourceSpan _createSpan(int offset, int len) {
+    return createSpanHelper(_unit.lineInfo, offset, offset + len,
+        _unit.element.source, _unitSourceCode);
+  }
+}
+
+SourceLocation locationForOffset(LineInfo lineInfo, Uri uri, int offset) {
+  var loc = lineInfo.getLocation(offset);
+  return new SourceLocation(offset,
+      sourceUrl: uri, line: loc.lineNumber - 1, column: loc.columnNumber - 1);
+}
+
+SourceSpanWithContext createSpanHelper(
+    LineInfo lineInfo, int start, int end, Source source, String content) {
+  var startLoc = locationForOffset(lineInfo, source.uri, start);
+  var endLoc = locationForOffset(lineInfo, source.uri, end);
+
+  var lineStart = startLoc.offset - startLoc.column;
+  // Find the end of the line. This is not exposed directly on LineInfo, but
+  // we can find it pretty easily.
+  // TODO(jmesserly): for now we do the simple linear scan. Ideally we can get
+  // some help from the LineInfo API.
+  int lineEnd = endLoc.offset;
+  int lineNum = lineInfo.getLocation(lineEnd).lineNumber;
+  while (lineEnd < content.length &&
+      lineInfo.getLocation(++lineEnd).lineNumber == lineNum);
+
+  var text = content.substring(start, end);
+  var lineText = content.substring(lineStart, lineEnd);
+  return new SourceSpanWithContext(startLoc, endLoc, text, lineText);
+}
+
+/// Describes an expected message that should be produced by the checker.
+class _ErrorExpectation {
+  final Level level;
+  final String typeName;
+  _ErrorExpectation(this.level, this.typeName);
+
+  static _ErrorExpectation _parse(String descriptor) {
+    var tokens = descriptor.split(':');
+    expect(tokens.length, 2, reason: 'invalid error descriptor');
+    var name = tokens[0].toUpperCase();
+    var typeName = tokens[1];
+
+    var level =
+        Level.LEVELS.firstWhere((l) => l.name == name, orElse: () => null);
+    expect(level, isNotNull,
+        reason: 'invalid level in error descriptor: `${tokens[0]}`');
+    expect(typeName, isNotNull,
+        reason: 'invalid type in error descriptor: ${tokens[1]}');
+    return new _ErrorExpectation(level, typeName);
+  }
+
+  static _ErrorExpectation parse(String descriptor) {
+    descriptor = descriptor.trim();
+    var tokens = descriptor.split(' ');
+    if (tokens.length == 1) return _parse(tokens[0]);
+    expect(tokens.length, 4, reason: 'invalid error descriptor');
+    expect(tokens[1], "should", reason: 'invalid error descriptor');
+    expect(tokens[2], "be", reason: 'invalid error descriptor');
+    if (tokens[0] == "pass") return null;
+    // TODO(leafp) For now, we just use whatever the current expectation is,
+    // eventually we could do more automated reporting here.
+    return _parse(tokens[0]);
+  }
+
+  String toString() => '$level $typeName';
+}
+
+/// Dart SDK which contains a mock implementation of the SDK libraries. May be
+/// used to speed up execution when most of the core libraries is not needed.
+class MockDartSdk implements DartSdk {
+  final Map<Uri, _MockSdkSource> _sources = {};
+  final bool reportMissing;
+  final Map<String, SdkLibrary> _libs = {};
+  final String sdkVersion = '0';
+  List<String> get uris => _sources.keys.map((uri) => '$uri').toList();
+  final AnalysisContext context = new SdkAnalysisContext();
+  DartUriResolver _resolver;
+  DartUriResolver get resolver => _resolver;
+
+  MockDartSdk(Map<String, String> sources, {this.reportMissing}) {
+    sources.forEach((uriString, contents) {
+      var uri = Uri.parse(uriString);
+      _sources[uri] = new _MockSdkSource(uri, contents);
+      _libs[uriString] = new SdkLibraryImpl(uri.path)
+        ..setDart2JsLibrary()
+        ..setVmLibrary();
+    });
+    _resolver = new DartUriResolver(this);
+    context.sourceFactory = new SourceFactory([_resolver]);
+  }
+
+  List<SdkLibrary> get sdkLibraries => _libs.values.toList();
+  SdkLibrary getSdkLibrary(String dartUri) => _libs[dartUri];
+  Source mapDartUri(String dartUri) => _getSource(Uri.parse(dartUri));
+
+  Source fromEncoding(UriKind kind, Uri uri) {
+    if (kind != UriKind.DART_URI) {
+      throw new UnsupportedError('expected dart: uri kind, got $kind.');
+    }
+    return _getSource(uri);
+  }
+
+  Source _getSource(Uri uri) {
+    var src = _sources[uri];
+    if (src == null) {
+      if (reportMissing) print('warning: missing mock for $uri.');
+      _sources[uri] =
+          src = new _MockSdkSource(uri, 'library dart.${uri.path};');
+    }
+    return src;
+  }
+
+  @override
+  Source fromFileUri(Uri uri) {
+    throw new UnsupportedError('MockDartSdk.fromFileUri');
+  }
+}
+
+class _MockSdkSource implements Source {
+  /// Absolute URI which this source can be imported from.
+  final Uri uri;
+  final String _contents;
+
+  _MockSdkSource(this.uri, this._contents);
+
+  bool exists() => true;
+
+  int get hashCode => uri.hashCode;
+
+  final int modificationStamp = 1;
+
+  TimestampedData<String> get contents =>
+      new TimestampedData(modificationStamp, _contents);
+
+  String get encoding => "${uriKind.encoding}$uri";
+
+  Source get source => this;
+
+  String get fullName => shortName;
+
+  String get shortName => uri.path;
+
+  UriKind get uriKind => UriKind.DART_URI;
+
+  bool get isInSystemLibrary => true;
+
+  Source resolveRelative(Uri relativeUri) =>
+      throw new UnsupportedError('not expecting relative urls in dart: mocks');
+
+  Uri resolveRelativeUri(Uri relativeUri) =>
+      throw new UnsupportedError('not expecting relative urls in dart: mocks');
+}
+
+/// Sample mock SDK sources.
+final Map<String, String> mockSdkSources = {
+  // The list of types below is derived from:
+  //   * types we use via our smoke queries, including HtmlElement and
+  //     types from `_typeHandlers` (deserialize.dart)
+  //   * types that are used internally by the resolver (see
+  //   _initializeFrom in resolver.dart).
+  'dart:core': '''
+        library dart.core;
+
+        void print(Object o) {}
+
+        class Object {
+          int get hashCode {}
+          Type get runtimeType {}
+          String toString(){}
+          bool ==(other){}
+        }
+        class Function {}
+        class StackTrace {}
+        class Symbol {}
+        class Type {}
+
+        class String {
+          String operator +(String other) {}
+        }
+        class bool {}
+        class num {
+          num operator +(num other) {}
+        }
+        class int extends num {
+          bool operator<(num other) {}
+          int operator-() {}
+        }
+        class double extends num {}
+        class DateTime {}
+        class Null {}
+
+        class Deprecated {
+          final String expires;
+          const Deprecated(this.expires);
+        }
+        const Object deprecated = const Deprecated("next release");
+        class _Override { const _Override(); }
+        const Object override = const _Override();
+        class _Proxy { const _Proxy(); }
+        const Object proxy = const _Proxy();
+
+        class Iterable<E> {
+          fold(initialValue, combine(previousValue, E element)) {}
+          Iterable map(f(E element)) {}
+        }
+        class List<E> implements Iterable<E> {
+          List([int length]);
+          List.filled(int length, E fill);
+        }
+        class Map<K, V> {
+          Iterable<K> get keys {}
+        }
+        ''',
+  'dart:async': '''
+        class Future<T> {
+          Future(computation()) {}
+          Future.value(T t) {}
+          Future then(onValue(T value)) {}
+          static Future<List> wait(Iterable<Future> futures) {}
+        }
+        class Stream<T> {}
+  ''',
+  'dart:html': '''
+        library dart.html;
+        class HtmlElement {}
+        ''',
+  'dart:math': '''
+        library dart.math;
+        class Random {
+          bool nextBool() {}
+        }
+        num min(num x, num y) {}
+        num max(num x, num y) {}
+        ''',
+};
+
+/// Returns all libraries transitively imported or exported from [start].
+List<LibraryElement> reachableLibraries(LibraryElement start) {
+  var results = <LibraryElement>[];
+  var seen = new Set();
+  void find(LibraryElement lib) {
+    if (seen.contains(lib)) return;
+    seen.add(lib);
+    results.add(lib);
+    lib.importedLibraries.forEach(find);
+    lib.exportedLibraries.forEach(find);
+  }
+  find(start);
+  return results;
+}
+
+String errorCodeName(ErrorCode errorCode) {
+  var name = errorCode.name;
+  final prefix = 'dev_compiler.';
+  if (name.startsWith(prefix)) {
+    return name.substring(prefix.length);
+  } else {
+    // TODO(jmesserly): this is for backwards compat, but not sure it's very
+    // useful to log this.
+    return 'AnalyzerMessage';
+  }
+}
+
+/// Returns an ANSII color escape sequence corresponding to [levelName]. Colors
+/// are defined for: severe, error, warning, or info. Returns null if the level
+/// name is not recognized.
+String colorOf(String levelName) {
+  levelName = levelName.toLowerCase();
+  if (levelName == 'shout' || levelName == 'severe' || levelName == 'error') {
+    return _RED_COLOR;
+  }
+  if (levelName == 'warning') return _MAGENTA_COLOR;
+  if (levelName == 'info') return _CYAN_COLOR;
+  return null;
+}
+
+const String _RED_COLOR = '\u001b[31m';
+const String _MAGENTA_COLOR = '\u001b[35m';
+const String _CYAN_COLOR = '\u001b[36m';
+const String GREEN_COLOR = '\u001b[32m';
+const String NO_COLOR = '\u001b[0m';
diff --git a/packages/analyzer/tool/generate_files b/packages/analyzer/tool/generate_files
new file mode 100755
index 0000000..4d0b220
--- /dev/null
+++ b/packages/analyzer/tool/generate_files
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+# This script executes code generation tools found in the analyzer
+# "tool" directory.
+
+set -e
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+SCRIPT_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+ROOT_DIR="$(cd "${SCRIPT_DIR}/../../.." ; pwd -P)"
+
+BIN_DIR="${ROOT_DIR}/sdk/bin"
+
+if [ -z "$DART_CONFIGURATION" ];
+then
+  DART_CONFIGURATION="ReleaseIA32"
+fi
+
+if [[ `uname` == 'Darwin' ]];
+then
+  BUILD_DIR="${ROOT_DIR}/xcodebuild/$DART_CONFIGURATION"
+else
+  BUILD_DIR="${ROOT_DIR}/out/$DART_CONFIGURATION"
+fi
+
+PKG_DIR="${BUILD_DIR}/packages"
+
+DART="${BIN_DIR}/dart"
+
+declare -a VM_OPTIONS
+VM_OPTIONS+=("--checked")
+VM_OPTIONS+=("--package-root=${PKG_DIR}")
+
+cd "${SCRIPT_DIR}"
+"${DART}" "${VM_OPTIONS[@]}" "task_dependency_graph/generate.dart"
diff --git a/packages/analyzer/tool/task_dependency_graph.dart b/packages/analyzer/tool/task_dependency_graph.dart
deleted file mode 100644
index 5da2976..0000000
--- a/packages/analyzer/tool/task_dependency_graph.dart
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * This file contains code to output a description of tasks and their
- * dependencies in ".dot" format.  Prior to running, the user should run "pub
- * get" in the analyzer directory to ensure that a "packages" folder exists.
- *
- * The ".dot" file is output to standard out.  To convert it to a pdf, store it
- * in a file (e.g. "tasks.dot"), and post-process it with
- * "dot tasks.dart -Tpdf -O".
- *
- * TODO(paulberry):
- * - Add general.dart and html.dart for completeness.
- * - Use Graphviz's "record" feature to produce more compact output
- *   (http://www.graphviz.org/content/node-shapes#record)
- * - Produce a warning if a result descriptor is found which isn't the output
- *   of exactly one task.
- * - Convert this tool to use package_config to find the package map.
- */
-library task_dependency_graph;
-
-import 'dart:io' hide File;
-
-import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:path/path.dart' as path;
-
-main() {
-  new Driver().run();
-}
-
-typedef void ResultDescriptorFinderCallback(PropertyAccessorElement element);
-
-class Driver {
-  PhysicalResourceProvider resourceProvider;
-  AnalysisContext context;
-  InterfaceType resultDescriptorType;
-  String rootDir;
-
-  void findResultDescriptors(
-      AstNode node, void callback(String descriptorName)) {
-    Set<PropertyAccessorElement> resultDescriptors =
-        new Set<PropertyAccessorElement>();
-    node.accept(new ResultDescriptorFinder(
-        resultDescriptorType, resultDescriptors.add));
-    for (PropertyAccessorElement resultDescriptor in resultDescriptors) {
-      callback(resultDescriptor.name);
-    }
-  }
-
-  /**
-   * Find the root directory of the analyzer package by proceeding
-   * upward to the 'tool' dir, and then going up one more directory.
-   */
-  String findRoot(String pathname) {
-    while (path.basename(pathname) != 'tool') {
-      String parent = path.dirname(pathname);
-      if (parent.length >= pathname.length) {
-        throw new Exception("Can't find root directory");
-      }
-      pathname = parent;
-    }
-    return path.dirname(pathname);
-  }
-
-  CompilationUnit getUnit(Source source) =>
-      context.resolveCompilationUnit2(source, source);
-
-  void run() {
-    rootDir = findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
-    resourceProvider = PhysicalResourceProvider.INSTANCE;
-    DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
-    context = AnalysisEngine.instance.createAnalysisContext();
-    JavaFile packagesDir = new JavaFile(path.join(rootDir, 'packages'));
-    List<UriResolver> uriResolvers = [
-      new DartUriResolver(sdk),
-      new PackageUriResolver(<JavaFile>[packagesDir]),
-      new FileUriResolver()
-    ];
-    context.sourceFactory = new SourceFactory(uriResolvers);
-    Source taskSource =
-        setupSource(path.join('lib', 'src', 'task', 'dart.dart'));
-    Source modelSource = setupSource(path.join('lib', 'task', 'model.dart'));
-    CompilationUnitElement modelElement = getUnit(modelSource).element;
-    InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type;
-    DartType dynamicType = context.typeProvider.dynamicType;
-    resultDescriptorType = modelElement
-        .getType('ResultDescriptor')
-        .type
-        .substitute4([dynamicType]);
-    CompilationUnit taskUnit = getUnit(taskSource);
-    CompilationUnitElement taskUnitElement = taskUnit.element;
-    print('digraph G {');
-    Set<String> results = new Set<String>();
-    for (ClassElement cls in taskUnitElement.types) {
-      if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) {
-        String task = cls.name;
-        // TODO(paulberry): node is deprecated.  What am I supposed to do
-        // instead?
-        findResultDescriptors(cls.getMethod('buildInputs').node,
-            (String input) {
-          results.add(input);
-          print('  $input -> $task');
-        });
-        findResultDescriptors(cls.getField('DESCRIPTOR').node, (String output) {
-          results.add(output);
-          print('  $task -> $output');
-        });
-      }
-    }
-    for (String result in results) {
-      print('  $result [shape=box]');
-    }
-    print('}');
-  }
-
-  Source setupSource(String filename) {
-    String filePath = path.join(rootDir, filename);
-    File file = resourceProvider.getResource(filePath);
-    Source source = file.createSource();
-    Uri restoredUri = context.sourceFactory.restoreUri(source);
-    if (restoredUri != null) {
-      source = file.createSource(restoredUri);
-    }
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.addedSource(source);
-    context.applyChanges(changeSet);
-    return source;
-  }
-}
-
-class ResultDescriptorFinder extends GeneralizingAstVisitor {
-  final InterfaceType resultDescriptorType;
-  final ResultDescriptorFinderCallback callback;
-
-  ResultDescriptorFinder(this.resultDescriptorType, this.callback);
-
-  @override
-  visitIdentifier(Identifier node) {
-    Element element = node.staticElement;
-    if (element is PropertyAccessorElement &&
-        element.isGetter &&
-        element.returnType.isSubtypeOf(resultDescriptorType)) {
-      callback(element);
-    }
-  }
-}
diff --git a/packages/analyzer/tool/task_dependency_graph/check_test.dart b/packages/analyzer/tool/task_dependency_graph/check_test.dart
new file mode 100644
index 0000000..a2d1118
--- /dev/null
+++ b/packages/analyzer/tool/task_dependency_graph/check_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library task_dependency_graph.check_test;
+
+import 'dart:io';
+
+import 'package:path/path.dart';
+
+import 'generate.dart';
+
+/**
+ * Check that the target file has been code generated.  If it hasn't tell the
+ * user to run generate.dart.
+ */
+main() {
+  String script = Platform.script.toFilePath(windows: Platform.isWindows);
+  Driver driver = new Driver();
+  if (!driver.checkFile()) {
+    print('${driver.file.absolute} does not have expected contents.');
+    print('Please regenerate using:');
+    String executable = Platform.executable;
+    String packageRoot = '';
+    if (Platform.packageRoot.isNotEmpty) {
+      packageRoot = ' --package-root=${Platform.packageRoot}';
+    }
+    String generateScript = join(dirname(script), 'generate.dart');
+    print('  $executable$packageRoot $generateScript');
+    exit(1);
+  } else {
+    print('Generated file is up to date.');
+  }
+}
diff --git a/packages/analyzer/tool/task_dependency_graph/generate.dart b/packages/analyzer/tool/task_dependency_graph/generate.dart
new file mode 100644
index 0000000..235c2b9
--- /dev/null
+++ b/packages/analyzer/tool/task_dependency_graph/generate.dart
@@ -0,0 +1,346 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * This file contains code to output a description of tasks and their
+ * dependencies in ".dot" format.  Prior to running, the user should run "pub
+ * get" in the analyzer directory to ensure that a "packages" folder exists.
+ *
+ * TODO(paulberry):
+ * - Add general.dart and html.dart for completeness.
+ * - Use Graphviz's "record" feature to produce more compact output
+ *   (http://www.graphviz.org/content/node-shapes#record)
+ * - Produce a warning if a result descriptor is found which isn't the output
+ *   of exactly one task.
+ * - Convert this tool to use package_config to find the package map.
+ */
+library task_dependency_graph.generate;
+
+import 'dart:io' hide File;
+import 'dart:io' as io;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:path/path.dart' as path;
+
+/**
+ * Generate the target .dot file.
+ */
+main() {
+  new Driver().generateFile();
+}
+
+typedef void GetterFinderCallback(PropertyAccessorElement element);
+
+class Driver {
+  PhysicalResourceProvider resourceProvider;
+  AnalysisContext context;
+  InterfaceType resultDescriptorType;
+  InterfaceType listOfResultDescriptorType;
+  ClassElement enginePluginClass;
+  CompilationUnitElement taskUnitElement;
+  InterfaceType extensionPointIdType;
+  final String rootDir;
+
+  Driver()
+      : rootDir =
+            findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
+
+  /**
+   * Get an [io.File] object corresponding to the file in which the generated
+   * graph should be output.
+   */
+  io.File get file => new io.File(
+      path.join(rootDir, 'tool', 'task_dependency_graph', 'tasks.dot'));
+
+  /**
+   * Determine if the output [file] contains the expected contents.
+   */
+  bool checkFile() {
+    String expectedContents = generateFileContents();
+    String actualContents = file.readAsStringSync();
+    // Normalize Windows line endings to Unix line endings so that the
+    // comparison doesn't fail on Windows.
+    actualContents = actualContents.replaceAll('\r\n', '\n');
+    return expectedContents == actualContents;
+  }
+
+  /**
+   * Starting at [node], find all calls to registerExtension() which refer to
+   * the given [extensionIdVariable], and execute [callback] for the associated
+   * result descriptors.
+   */
+  void findExtensions(AstNode node, TopLevelVariableElement extensionIdVariable,
+      void callback(descriptorName)) {
+    Set<PropertyAccessorElement> resultDescriptors =
+        new Set<PropertyAccessorElement>();
+    node.accept(new ExtensionFinder(
+        resultDescriptorType, extensionIdVariable, resultDescriptors.add));
+    for (PropertyAccessorElement resultDescriptor in resultDescriptors) {
+      callback(resultDescriptor.name);
+    }
+  }
+
+  /**
+   * Starting at [node], find all references to a getter of type
+   * `List<ResultDescriptor>`, and execute [callback] on the getter names.
+   */
+  void findResultDescriptorLists(
+      AstNode node, void callback(String descriptorListName)) {
+    Set<PropertyAccessorElement> resultDescriptorLists =
+        new Set<PropertyAccessorElement>();
+    node.accept(new GetterFinder(
+        listOfResultDescriptorType, resultDescriptorLists.add));
+    for (PropertyAccessorElement resultDescriptorList
+        in resultDescriptorLists) {
+      // We only care about result descriptor lists associated with getters in
+      // the engine plugin class.
+      if (resultDescriptorList.enclosingElement != enginePluginClass) {
+        continue;
+      }
+      callback(resultDescriptorList.name);
+    }
+  }
+
+  void findResultDescriptors(
+      AstNode node, void callback(String descriptorName)) {
+    Set<PropertyAccessorElement> resultDescriptors =
+        new Set<PropertyAccessorElement>();
+    node.accept(new GetterFinder(resultDescriptorType, resultDescriptors.add));
+    for (PropertyAccessorElement resultDescriptor in resultDescriptors) {
+      callback(resultDescriptor.name);
+    }
+  }
+
+  /**
+   * Generate the task dependency graph and write it to the output [file].
+   */
+  void generateFile() {
+    String fileContents = generateFileContents();
+    file.writeAsStringSync(fileContents);
+  }
+
+  /**
+   * Generate the task dependency graph and return it as a [String].
+   */
+  String generateFileContents() {
+    List<String> lines = <String>[];
+    resourceProvider = PhysicalResourceProvider.INSTANCE;
+    DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+    context = AnalysisEngine.instance.createAnalysisContext();
+    String packageRootPath;
+    if (Platform.packageRoot.isNotEmpty) {
+      packageRootPath = Platform.packageRoot;
+    } else {
+      packageRootPath = path.join(rootDir, 'packages');
+    }
+    JavaFile packagesDir = new JavaFile(packageRootPath);
+    List<UriResolver> uriResolvers = [
+      new DartUriResolver(sdk),
+      new PackageUriResolver(<JavaFile>[packagesDir]),
+      new FileUriResolver()
+    ];
+    context.sourceFactory = new SourceFactory(uriResolvers);
+    Source dartDartSource =
+        setupSource(path.join('lib', 'src', 'task', 'dart.dart'));
+    Source taskSource = setupSource(path.join('lib', 'plugin', 'task.dart'));
+    Source modelSource = setupSource(path.join('lib', 'task', 'model.dart'));
+    Source enginePluginSource =
+        setupSource(path.join('lib', 'src', 'plugin', 'engine_plugin.dart'));
+    CompilationUnitElement modelElement = getUnit(modelSource).element;
+    InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type;
+    DartType dynamicType = context.typeProvider.dynamicType;
+    resultDescriptorType = modelElement
+        .getType('ResultDescriptor')
+        .type
+        .substitute4([dynamicType]);
+    listOfResultDescriptorType =
+        context.typeProvider.listType.substitute4([resultDescriptorType]);
+    CompilationUnitElement enginePluginUnitElement =
+        getUnit(enginePluginSource).element;
+    enginePluginClass = enginePluginUnitElement.getType('EnginePlugin');
+    extensionPointIdType =
+        enginePluginUnitElement.getType('ExtensionPointId').type;
+    CompilationUnit dartDartUnit = getUnit(dartDartSource);
+    CompilationUnitElement dartDartUnitElement = dartDartUnit.element;
+    CompilationUnit taskUnit = getUnit(taskSource);
+    taskUnitElement = taskUnit.element;
+    Set<String> results = new Set<String>();
+    Set<String> resultLists = new Set<String>();
+    for (ClassElement cls in dartDartUnitElement.types) {
+      if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) {
+        String task = cls.name;
+        AstNode buildInputsAst = cls.getMethod('buildInputs').computeNode();
+        findResultDescriptors(buildInputsAst, (String input) {
+          results.add(input);
+          lines.add('  $input -> $task');
+        });
+        findResultDescriptorLists(buildInputsAst, (String input) {
+          resultLists.add(input);
+          lines.add('  $input -> $task');
+        });
+        findResultDescriptors(cls.getField('DESCRIPTOR').computeNode(), (String out) {
+          results.add(out);
+          lines.add('  $task -> $out');
+        });
+      }
+    }
+    AstNode enginePluginAst = enginePluginUnitElement.computeNode();
+    for (String resultList in resultLists) {
+      lines.add('  $resultList [shape=hexagon]');
+      TopLevelVariableElement extensionIdVariable = _getExtensionId(resultList);
+      findExtensions(enginePluginAst, extensionIdVariable, (String extension) {
+        results.add(extension);
+        lines.add('  $extension -> $resultList');
+      });
+    }
+    for (String result in results) {
+      lines.add('  $result [shape=box]');
+    }
+    lines.sort();
+    return '''
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// This file has been automatically generated.  Please do not edit it manually.
+// To regenerate the file, use the script
+// "pkg/analyzer/tool/task_dependency_graph/generate.dart".
+//
+// To render this graph using Graphviz (www.graphviz.org) use the command:
+// "dot tasks.dot -Tpdf -O".
+digraph G {
+${lines.join('\n')}
+}
+''';
+  }
+
+  CompilationUnit getUnit(Source source) =>
+      context.resolveCompilationUnit2(source, source);
+
+  Source setupSource(String filename) {
+    String filePath = path.join(rootDir, filename);
+    File file = resourceProvider.getResource(filePath);
+    Source source = file.createSource();
+    Uri restoredUri = context.sourceFactory.restoreUri(source);
+    if (restoredUri != null) {
+      source = file.createSource(restoredUri);
+    }
+    ChangeSet changeSet = new ChangeSet();
+    changeSet.addedSource(source);
+    context.applyChanges(changeSet);
+    return source;
+  }
+
+  /**
+   * Find the result list getter having name [resultListGetterName] in the
+   * [EnginePlugin] class, and use the [ExtensionPointId] annotation on that
+   * getter to find the associated [TopLevelVariableElement] which can be used
+   * to register extensions for that getter.
+   */
+  TopLevelVariableElement _getExtensionId(String resultListGetterName) {
+    PropertyAccessorElement getter =
+        enginePluginClass.getGetter(resultListGetterName);
+    for (ElementAnnotation annotation in getter.metadata) {
+      DartObjectImpl annotationValue = annotation.constantValue;
+      if (annotationValue.type.isSubtypeOf(extensionPointIdType)) {
+        String extensionPointId =
+            annotationValue.fields['extensionPointId'].toStringValue();
+        for (TopLevelVariableElement variable
+            in taskUnitElement.topLevelVariables) {
+          if (variable.name == extensionPointId) {
+            return variable;
+          }
+        }
+      }
+    }
+    throw new Exception(
+        'Could not find extension ID corresponding to $resultListGetterName');
+  }
+
+  /**
+   * Find the root directory of the analyzer package by proceeding
+   * upward to the 'tool' dir, and then going up one more directory.
+   */
+  static String findRoot(String pathname) {
+    while (path.basename(pathname) != 'tool') {
+      String parent = path.dirname(pathname);
+      if (parent.length >= pathname.length) {
+        throw new Exception("Can't find root directory");
+      }
+      pathname = parent;
+    }
+    return path.dirname(pathname);
+  }
+}
+
+/**
+ * Visitor that finds calls that register extension points.  Specifically, we
+ * look for calls of the form `method(extensionIdVariable, resultDescriptor)`,
+ * where `resultDescriptor` has type [resultDescriptorType], and we pass the
+ * corresponding result descriptor names to [callback].
+ */
+class ExtensionFinder extends GeneralizingAstVisitor {
+  final InterfaceType resultDescriptorType;
+  final TopLevelVariableElement extensionIdVariable;
+  final GetterFinderCallback callback;
+
+  ExtensionFinder(
+      this.resultDescriptorType, this.extensionIdVariable, this.callback);
+
+  @override
+  visitIdentifier(Identifier node) {
+    Element element = node.staticElement;
+    if (element is PropertyAccessorElement &&
+        element.isGetter &&
+        element.variable == extensionIdVariable) {
+      AstNode parent = node.parent;
+      if (parent is ArgumentList &&
+          parent.arguments.length == 2 &&
+          parent.arguments[0] == node) {
+        Expression extension = parent.arguments[1];
+        if (extension is Identifier) {
+          Element element = extension.staticElement;
+          if (element is PropertyAccessorElement &&
+              element.isGetter &&
+              element.returnType.isSubtypeOf(resultDescriptorType)) {
+            callback(element);
+            return;
+          }
+        }
+      }
+      throw new Exception('Could not decode extension setup: $parent');
+    }
+  }
+}
+
+/**
+ * Visitor that finds references to getters having a specific type (or a
+ * subtype of that type)
+ */
+class GetterFinder extends GeneralizingAstVisitor {
+  final InterfaceType type;
+  final GetterFinderCallback callback;
+
+  GetterFinder(this.type, this.callback);
+
+  @override
+  visitIdentifier(Identifier node) {
+    Element element = node.staticElement;
+    if (element is PropertyAccessorElement &&
+        element.isGetter &&
+        element.returnType.isSubtypeOf(type)) {
+      callback(element);
+    }
+  }
+}
diff --git a/packages/analyzer/tool/task_dependency_graph/tasks.dot b/packages/analyzer/tool/task_dependency_graph/tasks.dot
new file mode 100644
index 0000000..42c5f69
--- /dev/null
+++ b/packages/analyzer/tool/task_dependency_graph/tasks.dot
@@ -0,0 +1,245 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// This file has been automatically generated.  Please do not edit it manually.
+// To regenerate the file, use the script
+// "pkg/analyzer/tool/task_dependency_graph/generate.dart".
+//
+// To render this graph using Graphviz (www.graphviz.org) use the command:
+// "dot tasks.dot -Tpdf -O".
+digraph G {
+  BUILD_DIRECTIVES_ERRORS -> LibraryUnitErrorsTask
+  BUILD_DIRECTIVES_ERRORS [shape=box]
+  BUILD_LIBRARY_ERRORS -> LibraryUnitErrorsTask
+  BUILD_LIBRARY_ERRORS [shape=box]
+  BuildCompilationUnitElementTask -> COMPILATION_UNIT_CONSTANTS
+  BuildCompilationUnitElementTask -> COMPILATION_UNIT_ELEMENT
+  BuildCompilationUnitElementTask -> RESOLVED_UNIT1
+  BuildDirectiveElementsTask -> BUILD_DIRECTIVES_ERRORS
+  BuildDirectiveElementsTask -> LIBRARY_ELEMENT2
+  BuildEnumMemberElementsTask -> RESOLVED_UNIT2
+  BuildExportNamespaceTask -> LIBRARY_ELEMENT4
+  BuildLibraryElementTask -> BUILD_LIBRARY_ERRORS
+  BuildLibraryElementTask -> IS_LAUNCHABLE
+  BuildLibraryElementTask -> LIBRARY_ELEMENT1
+  BuildPublicNamespaceTask -> LIBRARY_ELEMENT3
+  BuildSourceExportClosureTask -> EXPORT_SOURCE_CLOSURE
+  BuildSourceImportExportClosureTask -> IMPORT_EXPORT_SOURCE_CLOSURE
+  BuildSourceImportExportClosureTask -> IS_CLIENT
+  BuildTypeProviderTask -> TYPE_PROVIDER
+  COMPILATION_UNIT_CONSTANTS -> EvaluateUnitConstantsTask
+  COMPILATION_UNIT_CONSTANTS [shape=box]
+  COMPILATION_UNIT_ELEMENT [shape=box]
+  CONSTANT_DEPENDENCIES -> ComputeConstantValueTask
+  CONSTANT_DEPENDENCIES [shape=box]
+  CONSTANT_VALUE -> ComputeConstantValueTask
+  CONSTANT_VALUE -> EvaluateUnitConstantsTask
+  CONSTANT_VALUE [shape=box]
+  CONTAINING_LIBRARIES -> DartErrorsTask
+  CONTAINING_LIBRARIES [shape=box]
+  CONTENT -> ScanDartTask
+  CONTENT [shape=box]
+  ComputeConstantDependenciesTask -> CONSTANT_DEPENDENCIES
+  ComputeConstantValueTask -> CONSTANT_VALUE
+  ComputeInferableStaticVariableDependenciesTask -> INFERABLE_STATIC_VARIABLE_DEPENDENCIES
+  ComputeLibraryCycleTask -> LIBRARY_CYCLE
+  ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
+  ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
+  ContainingLibrariesTask -> CONTAINING_LIBRARIES
+  DART_ERRORS -> LibraryErrorsReadyTask
+  DART_ERRORS [shape=box]
+  DART_SCRIPTS -> ScanDartTask
+  DART_SCRIPTS [shape=box]
+  DartErrorsTask -> DART_ERRORS
+  EXPLICITLY_IMPORTED_LIBRARIES [shape=box]
+  EXPORTED_LIBRARIES -> BuildDirectiveElementsTask
+  EXPORTED_LIBRARIES [shape=box]
+  EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
+  EXPORT_SOURCE_CLOSURE [shape=box]
+  EvaluateUnitConstantsTask -> RESOLVED_UNIT10
+  GatherUsedImportedElementsTask -> USED_IMPORTED_ELEMENTS
+  GatherUsedLocalElementsTask -> USED_LOCAL_ELEMENTS
+  GenerateHintsTask -> HINTS
+  GenerateLintsTask -> LINTS
+  HINTS -> LibraryUnitErrorsTask
+  HINTS [shape=box]
+  IMPORTED_LIBRARIES -> BuildDirectiveElementsTask
+  IMPORTED_LIBRARIES -> ResolveUnitTypeNamesTask
+  IMPORTED_LIBRARIES [shape=box]
+  IMPORT_EXPORT_SOURCE_CLOSURE -> ComputeLibraryCycleTask
+  IMPORT_EXPORT_SOURCE_CLOSURE -> PartiallyResolveUnitReferencesTask
+  IMPORT_EXPORT_SOURCE_CLOSURE -> ResolveLibraryReferencesTask
+  IMPORT_EXPORT_SOURCE_CLOSURE -> StrongModeVerifyUnitTask
+  IMPORT_EXPORT_SOURCE_CLOSURE -> VerifyUnitTask
+  IMPORT_EXPORT_SOURCE_CLOSURE [shape=box]
+  INCLUDED_PARTS -> BuildLibraryElementTask
+  INCLUDED_PARTS [shape=box]
+  INFERABLE_STATIC_VARIABLES_IN_UNIT -> InferStaticVariableTypesInUnitTask
+  INFERABLE_STATIC_VARIABLES_IN_UNIT [shape=box]
+  INFERABLE_STATIC_VARIABLE_DEPENDENCIES -> InferStaticVariableTypeTask
+  INFERABLE_STATIC_VARIABLE_DEPENDENCIES [shape=box]
+  INFERRED_STATIC_VARIABLE -> InferStaticVariableTypeTask
+  INFERRED_STATIC_VARIABLE -> InferStaticVariableTypesInUnitTask
+  INFERRED_STATIC_VARIABLE [shape=box]
+  IS_CLIENT [shape=box]
+  IS_LAUNCHABLE [shape=box]
+  InferInstanceMembersInUnitTask -> RESOLVED_UNIT8
+  InferStaticVariableTypeTask -> INFERRED_STATIC_VARIABLE
+  InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT6
+  LIBRARY_CYCLE [shape=box]
+  LIBRARY_CYCLE_DEPENDENCIES -> InferInstanceMembersInUnitTask
+  LIBRARY_CYCLE_DEPENDENCIES -> InferStaticVariableTypeTask
+  LIBRARY_CYCLE_DEPENDENCIES -> PartiallyResolveUnitReferencesTask
+  LIBRARY_CYCLE_DEPENDENCIES -> ResolveInstanceFieldsInUnitTask
+  LIBRARY_CYCLE_DEPENDENCIES [shape=box]
+  LIBRARY_CYCLE_UNITS -> InferInstanceMembersInUnitTask
+  LIBRARY_CYCLE_UNITS -> ResolveInstanceFieldsInUnitTask
+  LIBRARY_CYCLE_UNITS -> ResolveUnitTask
+  LIBRARY_CYCLE_UNITS [shape=box]
+  LIBRARY_ELEMENT -> EvaluateUnitConstantsTask
+  LIBRARY_ELEMENT [shape=box]
+  LIBRARY_ELEMENT1 -> BuildDirectiveElementsTask
+  LIBRARY_ELEMENT1 -> ResolveVariableReferencesTask
+  LIBRARY_ELEMENT1 [shape=box]
+  LIBRARY_ELEMENT2 -> BuildPublicNamespaceTask
+  LIBRARY_ELEMENT2 -> BuildSourceExportClosureTask
+  LIBRARY_ELEMENT2 -> BuildSourceImportExportClosureTask
+  LIBRARY_ELEMENT2 -> ComputeLibraryCycleTask
+  LIBRARY_ELEMENT2 [shape=box]
+  LIBRARY_ELEMENT3 -> BuildExportNamespaceTask
+  LIBRARY_ELEMENT3 -> BuildTypeProviderTask
+  LIBRARY_ELEMENT3 [shape=box]
+  LIBRARY_ELEMENT4 -> ResolveLibraryTypeNamesTask
+  LIBRARY_ELEMENT4 -> ResolveUnitTypeNamesTask
+  LIBRARY_ELEMENT4 [shape=box]
+  LIBRARY_ELEMENT5 -> PartiallyResolveUnitReferencesTask
+  LIBRARY_ELEMENT5 -> ResolveInstanceFieldsInUnitTask
+  LIBRARY_ELEMENT5 -> ResolveLibraryReferencesTask
+  LIBRARY_ELEMENT5 -> ResolveUnitTask
+  LIBRARY_ELEMENT5 [shape=box]
+  LIBRARY_ERRORS_READY [shape=box]
+  LIBRARY_UNIT_ERRORS -> dartErrorsForUnit
+  LIBRARY_UNIT_ERRORS [shape=box]
+  LINE_INFO -> ParseDartTask
+  LINE_INFO [shape=box]
+  LINTS -> LibraryUnitErrorsTask
+  LINTS [shape=box]
+  LibraryErrorsReadyTask -> LIBRARY_ERRORS_READY
+  LibraryUnitErrorsTask -> LIBRARY_UNIT_ERRORS
+  MODIFICATION_TIME -> ParseDartTask
+  MODIFICATION_TIME [shape=box]
+  PARSED_UNIT -> BuildCompilationUnitElementTask
+  PARSED_UNIT [shape=box]
+  PARSE_ERRORS -> dartErrorsForSource
+  PARSE_ERRORS [shape=box]
+  ParseDartTask -> EXPLICITLY_IMPORTED_LIBRARIES
+  ParseDartTask -> EXPORTED_LIBRARIES
+  ParseDartTask -> IMPORTED_LIBRARIES
+  ParseDartTask -> INCLUDED_PARTS
+  ParseDartTask -> PARSED_UNIT
+  ParseDartTask -> PARSE_ERRORS
+  ParseDartTask -> SOURCE_KIND
+  ParseDartTask -> UNITS
+  PartiallyResolveUnitReferencesTask -> INFERABLE_STATIC_VARIABLES_IN_UNIT
+  PartiallyResolveUnitReferencesTask -> RESOLVED_UNIT5
+  REFERENCED_NAMES [shape=box]
+  RESOLVED_UNIT -> GenerateHintsTask
+  RESOLVED_UNIT -> GenerateLintsTask
+  RESOLVED_UNIT -> VerifyUnitTask
+  RESOLVED_UNIT [shape=box]
+  RESOLVED_UNIT1 -> BuildDirectiveElementsTask
+  RESOLVED_UNIT1 -> BuildEnumMemberElementsTask
+  RESOLVED_UNIT1 -> BuildLibraryElementTask
+  RESOLVED_UNIT1 [shape=box]
+  RESOLVED_UNIT10 -> StrongModeVerifyUnitTask
+  RESOLVED_UNIT10 [shape=box]
+  RESOLVED_UNIT2 -> ResolveUnitTypeNamesTask
+  RESOLVED_UNIT2 [shape=box]
+  RESOLVED_UNIT3 -> ResolveLibraryTypeNamesTask
+  RESOLVED_UNIT3 -> ResolveVariableReferencesTask
+  RESOLVED_UNIT3 [shape=box]
+  RESOLVED_UNIT4 -> PartiallyResolveUnitReferencesTask
+  RESOLVED_UNIT4 [shape=box]
+  RESOLVED_UNIT5 -> ComputeInferableStaticVariableDependenciesTask
+  RESOLVED_UNIT5 -> InferStaticVariableTypeTask
+  RESOLVED_UNIT5 -> InferStaticVariableTypesInUnitTask
+  RESOLVED_UNIT5 [shape=box]
+  RESOLVED_UNIT6 -> ResolveInstanceFieldsInUnitTask
+  RESOLVED_UNIT6 [shape=box]
+  RESOLVED_UNIT7 -> InferInstanceMembersInUnitTask
+  RESOLVED_UNIT7 [shape=box]
+  RESOLVED_UNIT8 -> InferInstanceMembersInUnitTask
+  RESOLVED_UNIT8 -> InferStaticVariableTypeTask
+  RESOLVED_UNIT8 -> PartiallyResolveUnitReferencesTask
+  RESOLVED_UNIT8 -> ResolveInstanceFieldsInUnitTask
+  RESOLVED_UNIT8 -> ResolveUnitTask
+  RESOLVED_UNIT8 [shape=box]
+  RESOLVED_UNIT9 -> ComputeConstantDependenciesTask
+  RESOLVED_UNIT9 -> EvaluateUnitConstantsTask
+  RESOLVED_UNIT9 -> GatherUsedImportedElementsTask
+  RESOLVED_UNIT9 -> GatherUsedLocalElementsTask
+  RESOLVED_UNIT9 -> ResolveLibraryReferencesTask
+  RESOLVED_UNIT9 [shape=box]
+  RESOLVE_TYPE_NAMES_ERRORS -> LibraryUnitErrorsTask
+  RESOLVE_TYPE_NAMES_ERRORS [shape=box]
+  RESOLVE_UNIT_ERRORS -> LibraryUnitErrorsTask
+  RESOLVE_UNIT_ERRORS [shape=box]
+  ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT7
+  ResolveLibraryReferencesTask -> LIBRARY_ELEMENT
+  ResolveLibraryReferencesTask -> REFERENCED_NAMES
+  ResolveLibraryTypeNamesTask -> LIBRARY_ELEMENT5
+  ResolveUnitTask -> RESOLVED_UNIT9
+  ResolveUnitTask -> RESOLVE_UNIT_ERRORS
+  ResolveUnitTypeNamesTask -> RESOLVED_UNIT3
+  ResolveUnitTypeNamesTask -> RESOLVE_TYPE_NAMES_ERRORS
+  ResolveVariableReferencesTask -> RESOLVED_UNIT4
+  ResolveVariableReferencesTask -> VARIABLE_REFERENCE_ERRORS
+  SCAN_ERRORS -> dartErrorsForSource
+  SCAN_ERRORS [shape=box]
+  SOURCE_KIND -> BuildDirectiveElementsTask
+  SOURCE_KIND [shape=box]
+  STRONG_MODE_ERRORS -> LibraryUnitErrorsTask
+  STRONG_MODE_ERRORS [shape=box]
+  ScanDartTask -> LINE_INFO
+  ScanDartTask -> SCAN_ERRORS
+  ScanDartTask -> TOKEN_STREAM
+  StrongModeVerifyUnitTask -> RESOLVED_UNIT
+  StrongModeVerifyUnitTask -> STRONG_MODE_ERRORS
+  TOKEN_STREAM -> ParseDartTask
+  TOKEN_STREAM [shape=box]
+  TYPE_PROVIDER -> BuildEnumMemberElementsTask
+  TYPE_PROVIDER -> ComputeConstantDependenciesTask
+  TYPE_PROVIDER -> ComputeConstantValueTask
+  TYPE_PROVIDER -> GenerateHintsTask
+  TYPE_PROVIDER -> InferInstanceMembersInUnitTask
+  TYPE_PROVIDER -> InferStaticVariableTypeTask
+  TYPE_PROVIDER -> PartiallyResolveUnitReferencesTask
+  TYPE_PROVIDER -> ResolveInstanceFieldsInUnitTask
+  TYPE_PROVIDER -> ResolveUnitTask
+  TYPE_PROVIDER -> ResolveUnitTypeNamesTask
+  TYPE_PROVIDER -> ResolveVariableReferencesTask
+  TYPE_PROVIDER -> StrongModeVerifyUnitTask
+  TYPE_PROVIDER -> VerifyUnitTask
+  TYPE_PROVIDER [shape=box]
+  UNITS -> GenerateHintsTask
+  UNITS -> LibraryErrorsReadyTask
+  UNITS -> ResolveLibraryReferencesTask
+  UNITS -> ResolveLibraryTypeNamesTask
+  UNITS -> StrongModeVerifyUnitTask
+  UNITS -> VerifyUnitTask
+  UNITS [shape=box]
+  USED_IMPORTED_ELEMENTS -> GenerateHintsTask
+  USED_IMPORTED_ELEMENTS [shape=box]
+  USED_LOCAL_ELEMENTS -> GenerateHintsTask
+  USED_LOCAL_ELEMENTS [shape=box]
+  VARIABLE_REFERENCE_ERRORS -> LibraryUnitErrorsTask
+  VARIABLE_REFERENCE_ERRORS [shape=box]
+  VERIFY_ERRORS -> LibraryUnitErrorsTask
+  VERIFY_ERRORS [shape=box]
+  VerifyUnitTask -> VERIFY_ERRORS
+  dartErrorsForSource -> DartErrorsTask
+  dartErrorsForSource [shape=hexagon]
+  dartErrorsForUnit -> DartErrorsTask
+  dartErrorsForUnit [shape=hexagon]
+}
diff --git a/packages/async/CHANGELOG.md b/packages/async/CHANGELOG.md
index 39d204b..5801872 100644
--- a/packages/async/CHANGELOG.md
+++ b/packages/async/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 1.4.0
+
+- Added `AsyncMemoizer.future`, which allows the result to be accessed before
+  `runOnce()` is called.
+
+- Added `RestartableTimer`, a non-periodic timer that can be reset over and
+  over.
+
 ## 1.3.0
 
 - Added `StreamCompleter` class for creating a stream now and providing its
diff --git a/packages/async/lib/async.dart b/packages/async/lib/async.dart
index 71a1849..9da3552 100644
--- a/packages/async/lib/async.dart
+++ b/packages/async/lib/async.dart
@@ -6,6 +6,7 @@
 
 export "result.dart";
 export "src/async_memoizer.dart";
+export "src/cancelable_operation.dart";
 export "src/delegate/event_sink.dart";
 export "src/delegate/future.dart";
 export "src/delegate/sink.dart";
@@ -13,6 +14,7 @@
 export "src/delegate/stream_sink.dart";
 export "src/delegate/stream_subscription.dart";
 export "src/future_group.dart";
+export "src/restartable_timer.dart";
 export "src/result_future.dart";
 export "src/stream_completer.dart";
 export "src/stream_group.dart";
diff --git a/packages/async/lib/src/async_memoizer.dart b/packages/async/lib/src/async_memoizer.dart
index 68a6c80..41c3dae 100644
--- a/packages/async/lib/src/async_memoizer.dart
+++ b/packages/async/lib/src/async_memoizer.dart
@@ -31,17 +31,18 @@
 class AsyncMemoizer<T> {
   /// The future containing the method's result.
   ///
-  /// This will be `null` if [run] hasn't been called yet.
-  Future<T> _future;
+  /// This can be accessed at any time, and will fire once [runOnce] is called.
+  Future<T> get future => _completer.future;
+  final _completer = new Completer();
 
   /// Whether [run] has been called yet.
-  bool get hasRun => _future != null;
+  bool get hasRun => _completer.isCompleted;
 
   /// Runs the function, [computation], if it hasn't been run before.
   ///
   /// If [run] has already been called, this returns the original result.
   Future<T> runOnce(computation()) {
-    if (_future == null) _future = new Future.sync(computation);
-    return _future;
+    if (!hasRun) _completer.complete(new Future.sync(computation));
+    return future;
   }
 }
diff --git a/packages/async/lib/src/cancelable_operation.dart b/packages/async/lib/src/cancelable_operation.dart
new file mode 100644
index 0000000..a7fe6a8
--- /dev/null
+++ b/packages/async/lib/src/cancelable_operation.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library async.cancelable_operation;
+
+import 'dart:async';
+
+import 'package:async/async.dart';
+
+/// An asynchronuos operation that can be cancelled.
+///
+/// The value of this operation is exposed as [value]. When this operation is
+/// cancelled, [value] won't complete either successfully or with an error. If
+/// [value] has already completed, cancelling the operation does nothing.
+class CancelableOperation<T> {
+  /// The completer that produced this operation.
+  ///
+  /// This is canceled when [cancel] is called.
+  final CancelableCompleter<T> _completer;
+
+  CancelableOperation._(this._completer);
+
+  /// Creates a [CancelableOperation] wrapping [inner].
+  ///
+  /// When this operation is canceled, [onCancel] will be called and any value
+  /// or error produced by [inner] will be discarded. The callback may return a
+  /// Future to indicate that asynchronous work has to be done to cancel the
+  /// future; this Future will be returned by [cancel].
+  ///
+  /// [onCancel] will be called synchronously when the operation is canceled.
+  /// It's guaranteed to only be called once.
+  factory CancelableOperation.fromFuture(Future<T> inner, {onCancel()}) {
+    var completer = new CancelableCompleter<T>(onCancel: onCancel);
+    completer.complete(inner);
+    return completer.operation;
+  }
+
+  /// The value returned by the operation.
+  Future<T> get value => _completer._inner.future;
+
+  /// Creates a [Stream] containing the result of this operation.
+  ///
+  /// This is like `value.asStream()`, but if a subscription to the stream is
+  /// canceled, this is as well.
+  Stream<T> asStream() {
+    var controller = new StreamController<T>(
+        sync: true, onCancel: _completer._cancel);
+
+    value.then((value) {
+      controller.add(value);
+      controller.close();
+    }, onError: (error, stackTrace) {
+      controller.addError(error, stackTrace);
+      controller.close();
+    });
+    return controller.stream;
+  }
+
+  /// Cancels this operation.
+  ///
+  /// This returns the [Future] returned by the [CancelableCompleter]'s
+  /// `onCancel` callback. Unlike [Stream.cancel], it never returns `null`.
+  Future cancel() => _completer._cancel();
+}
+
+/// A completer for a [CancelableOperation].
+class CancelableCompleter<T> {
+  /// The completer for the wrapped future.
+  final Completer<T> _inner;
+
+  /// The callback to call if the future is canceled.
+  final ZoneCallback _onCancel;
+
+  /// Creates a new completer for a [CancelableOperation].
+  ///
+  /// When the future operation canceled, as long as the completer hasn't yet
+  /// completed, [onCancel] is called. The callback may return a [Future]; if
+  /// so, that [Future] is returned by [CancelableOperation.cancel].
+  ///
+  /// [onCancel] will be called synchronously when the operation is canceled.
+  /// It's guaranteed to only be called once.
+  CancelableCompleter({onCancel()})
+      : _onCancel = onCancel,
+        _inner = new Completer<T>() {
+    _operation = new CancelableOperation<T>._(this);
+  }
+
+  /// The operation controlled by this completer.
+  CancelableOperation<T> get operation => _operation;
+  CancelableOperation<T> _operation;
+
+  /// Whether the completer has completed.
+  bool get isCompleted => _isCompleted;
+  bool _isCompleted = false;
+
+  /// Whether the completer was canceled before being completed.
+  bool get isCanceled => _isCanceled;
+  bool _isCanceled = false;
+
+  /// The memoizer for [_cancel].
+  final _cancelMemo = new AsyncMemoizer();
+
+  /// Completes [operation] to [value].
+  ///
+  /// If [value] is a [Future], this will complete to the result of that
+  /// [Future] once it completes.
+  void complete([value]) {
+    if (_isCompleted) throw new StateError("Operation already completed");
+    _isCompleted = true;
+
+    if (value is! Future) {
+      if (_isCanceled) return;
+      _inner.complete(value);
+      return;
+    }
+
+    if (_isCanceled) {
+      // Make sure errors from [value] aren't top-leveled.
+      value.catchError((_) {});
+      return;
+    }
+
+    value.then((result) {
+      if (_isCanceled) return;
+      _inner.complete(result);
+    }, onError: (error, stackTrace) {
+      if (_isCanceled) return;
+      _inner.completeError(error, stackTrace);
+    });
+  }
+
+  /// Completes [operation] to [error].
+  void completeError(Object error, [StackTrace stackTrace]) {
+    if (_isCompleted) throw new StateError("Operation already completed");
+    _isCompleted = true;
+
+    if (_isCanceled) return;
+    _inner.completeError(error, stackTrace);
+  }
+
+  /// Cancel the completer.
+  Future _cancel() => _cancelMemo.runOnce(() {
+    if (_inner.isCompleted) return null;
+    _isCanceled = true;
+    if (_onCancel != null) return _onCancel();
+  });
+}
diff --git a/packages/async/lib/src/restartable_timer.dart b/packages/async/lib/src/restartable_timer.dart
new file mode 100644
index 0000000..05196d2
--- /dev/null
+++ b/packages/async/lib/src/restartable_timer.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library async.restartable_timer;
+
+import 'dart:async';
+
+/// A non-periodic timer that can be restarted any number of times.
+///
+/// Once restarted (via [reset]), the timer counts down from its original
+/// duration again.
+class RestartableTimer implements Timer {
+  /// The duration of the timer.
+  final Duration _duration;
+
+  /// The callback to call when the timer fires.
+  final ZoneCallback _callback;
+
+  /// The timer for the current or most recent countdown.
+  ///
+  /// This timer is canceled and overwritten every time this [RestartableTimer]
+  /// is reset.
+  Timer _timer;
+
+  /// Creates a new timer.
+  ///
+  /// The [callback] function is invoked after the given [duration]. Unlike a
+  /// normal non-periodic [Timer], [callback] may be called more than once.
+  RestartableTimer(this._duration, this._callback) {
+    _timer = new Timer(_duration, _callback);
+  }
+
+  bool get isActive => _timer.isActive;
+
+  /// Restarts the timer so that it counts down from its original duration
+  /// again.
+  ///
+  /// This restarts the timer even if it has already fired or has been canceled.
+  void reset() {
+    _timer.cancel();
+    _timer = new Timer(_duration, _callback);
+  }
+
+  void cancel() {
+    _timer.cancel();
+  }
+}
diff --git a/packages/async/lib/src/stream_queue.dart b/packages/async/lib/src/stream_queue.dart
index 36d03ef..09b3a75 100644
--- a/packages/async/lib/src/stream_queue.dart
+++ b/packages/async/lib/src/stream_queue.dart
@@ -60,15 +60,17 @@
 ///
 /// When you need no further events the `StreamQueue` should be closed
 /// using [cancel]. This releases the underlying stream subscription.
-class StreamQueue<T> {
+abstract class StreamQueue<T> {
   // This class maintains two queues: one of events and one of requests.
   // The active request (the one in front of the queue) is called with
-  // the current event queue when it becomes active.
+  // the current event queue when it becomes active, every time a
+  // new event arrives, and when the event source closes.
   //
-  // If the request returns true, it's complete and will be removed from the
+  // If the request returns `true`, it's complete and will be removed from the
   // request queue.
-  // If the request returns false, it needs more events, and will be called
-  // again when new events are available.
+  // If the request returns `false`, it needs more events, and will be called
+  // again when new events are available. It may trigger a call itself by
+  // calling [_updateRequests].
   // The request can remove events that it uses, or keep them in the event
   // queue until it has all that it needs.
   //
@@ -77,16 +79,7 @@
   // potentially a request that takes either five or zero events, determined
   // by the content of the fifth event.
 
-  /// Source of events.
-  final Stream _sourceStream;
-
-  /// Subscription on [_sourceStream] while listening for events.
-  ///
-  /// Set to subscription when listening, and set to `null` when the
-  /// subscription is done (and [_isDone] is set to true).
-  StreamSubscription _subscription;
-
-  /// Whether we have listened on [_sourceStream] and the subscription is done.
+  /// Whether the event source is done.
   bool _isDone = false;
 
   /// Whether a closing operation has been performed on the stream queue.
@@ -103,8 +96,9 @@
   final Queue<_EventRequest> _requestQueue = new Queue();
 
   /// Create a `StreamQueue` of the events of [source].
-  StreamQueue(Stream source)
-      : _sourceStream = source;
+  factory StreamQueue(Stream source) = _StreamQueue<T>;
+
+  StreamQueue._();
 
   /// Asks if the stream has any more events.
   ///
@@ -115,6 +109,8 @@
   ///
   /// Can be used before using [next] to avoid getting an error in the
   /// future returned by `next` in the case where there are no more events.
+  /// Another alternative is to use `take(1)` which returns either zero or
+  /// one events.
   Future<bool> get hasNext {
     if (!_isClosed) {
       var hasNextRequest = new _HasNextRequest();
@@ -216,15 +212,15 @@
     throw _failClosed();
   }
 
-  /// Cancels the underlying stream subscription.
+  /// Cancels the underlying event source.
   ///
   /// If [immediate] is `false` (the default), the cancel operation waits until
   /// all previously requested events have been processed, then it cancels the
   /// subscription providing the events.
   ///
-  /// If [immediate] is `true`, the subscription is instead canceled
-  /// immediately. Any pending events complete with a 'closed'-event, as though
-  /// the stream had closed by itself.
+  /// If [immediate] is `true`, the source is instead canceled
+  /// immediately. Any pending events are completed as though the underlying
+  /// stream had closed.
   ///
   /// The returned future completes with the result of calling
   /// `cancel`.
@@ -242,13 +238,84 @@
       return request.future;
     }
 
-    if (_isDone) return new Future.value();
-    if (_subscription == null) _subscription = _sourceStream.listen(null);
-    var future = _subscription.cancel();
-    _onDone();
-    return future;
+    if (_isDone && _eventQueue.isEmpty) return new Future.value();
+    return _cancel();
   }
 
+  // ------------------------------------------------------------------
+  // Methods that may be called from the request implementations to
+  // control the even stream.
+
+  /// Matches events with requests.
+  ///
+  /// Called after receiving an event or when the event source closes.
+  ///
+  /// May be called by requests which have returned `false` (saying they
+  /// are not yet done) so they can be checked again before any new
+  /// events arrive.
+  /// Any request returing `false` from `update` when `isDone` is `true`
+  /// *must* call `_updateRequests` when they are ready to continue
+  /// (since no further events will trigger the call).
+  void _updateRequests() {
+    while (_requestQueue.isNotEmpty) {
+      if (_requestQueue.first.update(_eventQueue, _isDone)) {
+        _requestQueue.removeFirst();
+      } else {
+        return;
+      }
+    }
+
+    if (!_isDone) {
+      _pause();
+    }
+  }
+
+  /// Extracts a stream from the event source and makes this stream queue
+  /// unusable.
+  ///
+  /// Can only be used by the very last request (the stream queue must
+  /// be closed by that request).
+  /// Only used by [rest].
+  Stream _extractStream();
+
+  /// Requests that the event source pauses events.
+  ///
+  /// This is called automatically when the request queue is empty.
+  ///
+  /// The event source is restarted by the next call to [_ensureListening].
+  void _pause();
+
+  /// Ensures that we are listening on events from the event source.
+  ///
+  /// Starts listening for the first time or resumes after a [_pause].
+  ///
+  /// Is called automatically if a request requires more events.
+  void _ensureListening();
+
+  /// Cancels the underlying event source.
+  Future _cancel();
+
+  // ------------------------------------------------------------------
+  // Methods called by the event source to add events or say that it's
+  // done.
+
+  /// Called when the event source adds a new data or error event.
+  /// Always calls [_updateRequests] after adding.
+  void _addResult(Result result) {
+    _eventQueue.add(result);
+    _updateRequests();
+  }
+
+  /// Called when the event source is done.
+  /// Always calls [_updateRequests] after adding.
+  void _close() {
+    _isDone = true;
+    _updateRequests();
+  }
+
+  // ------------------------------------------------------------------
+  // Internal helper methods.
+
   /// Returns an error for when a request is made after cancel.
   ///
   /// Returns a [StateError] with a message saying that either
@@ -257,99 +324,92 @@
     return new StateError("Already cancelled");
   }
 
-  // Callbacks receiving the events of the source stream.
-
-  void _onData(T data) {
-    _eventQueue.add(new Result.value(data));
-    _checkQueues();
-  }
-
-  void _onError(error, StackTrace stack) {
-    _eventQueue.add(new Result.error(error, stack));
-    _checkQueues();
-  }
-
-  void _onDone() {
-    _subscription = null;
-    _isDone = true;
-    _closeAllRequests();
-  }
-
-  // Request queue management.
-
   /// Adds a new request to the queue.
+  ///
+  /// If the request queue is empty and the request can be completed
+  /// immediately, it skips the queue.
   void _addRequest(_EventRequest request) {
-    if (_isDone) {
-      assert(_requestQueue.isEmpty);
-      if (!request.addEvents(_eventQueue)) {
-        request.close(_eventQueue);
-      }
-      return;
-    }
     if (_requestQueue.isEmpty) {
-      if (request.addEvents(_eventQueue)) return;
+      if (request.update(_eventQueue, _isDone)) return;
       _ensureListening();
     }
     _requestQueue.add(request);
   }
+}
 
-  /// Ensures that we are listening on events from [_sourceStream].
+
+/// The default implementation of [StreamQueue].
+///
+/// This queue gets its events from a stream which is listened
+/// to when a request needs events.
+class _StreamQueue<T> extends StreamQueue<T> {
+  /// Source of events.
+  final Stream _sourceStream;
+
+  /// Subscription on [_sourceStream] while listening for events.
   ///
-  /// Resumes subscription on [_sourceStream], or creates it if necessary.
+  /// Set to subscription when listening, and set to `null` when the
+  /// subscription is done (and [_isDone] is set to true).
+  StreamSubscription _subscription;
+
+  _StreamQueue(this._sourceStream) : super._();
+
+  Future _cancel() {
+    if (_isDone) return null;
+    if (_subscription == null) _subscription = _sourceStream.listen(null);
+    var future = _subscription.cancel();
+    _close();
+    return future;
+  }
+
   void _ensureListening() {
     assert(!_isDone);
     if (_subscription == null) {
       _subscription =
-          _sourceStream.listen(_onData, onError: _onError, onDone: _onDone);
+          _sourceStream.listen(
+              (data) {
+                _addResult(new Result.value(data));
+              },
+              onError: (error, StackTrace stackTrace) {
+                _addResult(new Result.error(error, stackTrace));
+              },
+              onDone: () {
+                _subscription = null;
+                this._close();
+              });
     } else {
       _subscription.resume();
     }
   }
 
-  /// Removes all requests and closes them.
-  ///
-  /// Used when the source stream is done.
-  /// After this, no further requests will be added to the queue,
-  /// requests are immediately served entirely by events already in the event
-  /// queue, if any.
-  void _closeAllRequests() {
-    assert(_isDone);
-    while (_requestQueue.isNotEmpty) {
-      var request = _requestQueue.removeFirst();
-      if (!request.addEvents(_eventQueue)) {
-        request.close(_eventQueue);
-      }
-    }
+  void _pause() {
+    _subscription.pause();
   }
 
-  /// Matches events with requests.
-  ///
-  /// Called after receiving an event.
-  void _checkQueues() {
-    while (_requestQueue.isNotEmpty) {
-      if (_requestQueue.first.addEvents(_eventQueue)) {
-        _requestQueue.removeFirst();
-      } else {
-        return;
-      }
-    }
-    if (!_isDone) {
-      _subscription.pause();
-    }
-  }
-
-  /// Extracts the subscription and makes this stream queue unusable.
-  ///
-  /// Can only be used by the very last request.
-  StreamSubscription _dispose() {
+  Stream<T> _extractStream() {
     assert(_isClosed);
+    if (_isDone) {
+      return new Stream<T>.empty();
+    }
+
+    if (_subscription == null) {
+      return _sourceStream;
+    }
+
     var subscription = _subscription;
     _subscription = null;
     _isDone = true;
-    return subscription;
+
+    var wasPaused = subscription.isPaused;
+    var result = new SubscriptionStream<T>(subscription);
+    // Resume after creating stream because that pauses the subscription too.
+    // This way there won't be a short resumption in the middle.
+    if (wasPaused) subscription.resume();
+    return result;
   }
 }
 
+
 /// Request object that receives events when they arrive, until fulfilled.
 ///
 /// Each request that cannot be fulfilled immediately is represented by
@@ -367,7 +427,7 @@
 abstract class _EventRequest {
   /// Handle available events.
   ///
-  /// The available events are provided as a queue. The `addEvents` function
+  /// The available events are provided as a queue. The `update` function
   /// should only remove events from the front of the event queue, e.g.,
   /// using [removeFirst].
   ///
@@ -382,22 +442,10 @@
   /// This method is called when a request reaches the front of the request
   /// queue, and if it returns `false`, it's called again every time a new event
   /// becomes available, or when the stream closes.
-  bool addEvents(Queue<Result> events);
-
-  /// Complete the request.
-  ///
-  /// This is called when the source stream is done before the request
-  /// had a chance to receive all its events. That is, after a call
-  /// to [addEvents] has returned `false`.
-  /// If there are any unused events available, they are in the [events] queue.
-  /// No further events will become available.
-  ///
-  /// The queue should only remove events from the front of the event queue,
-  /// e.g., using [removeFirst].
-  ///
-  /// If the request kept events in the queue after an [addEvents] call,
-  /// this is the last chance to use them.
-  void close(Queue<Result> events);
+  /// If the function returns `false` when the stream has already closed
+  /// ([isDone] is true), then the request must call
+  /// [StreamQueue._updateRequests] itself when it's ready to continue.
+  bool update(Queue<Result> events, bool isDone);
 }
 
 /// Request for a [StreamQueue.next] call.
@@ -412,16 +460,18 @@
 
   Future<T> get future => _completer.future;
 
-  bool addEvents(Queue<Result> events) {
-    if (events.isEmpty) return false;
-    events.removeFirst().complete(_completer);
-    return true;
-  }
-
-  void close(Queue<Result> events) {
-    var errorFuture =
-        new Future.sync(() => throw new StateError("No elements"));
-    _completer.complete(errorFuture);
+  bool update(Queue<Result> events, bool isDone) {
+    if (events.isNotEmpty) {
+      events.removeFirst().complete(_completer);
+      return true;
+    }
+    if (isDone) {
+      var errorFuture =
+          new Future.sync(() => throw new StateError("No elements"));
+      _completer.complete(errorFuture);
+      return true;
+    }
+    return false;
   }
 }
 
@@ -443,22 +493,22 @@
   /// The future completed when the correct number of events have been skipped.
   Future get future => _completer.future;
 
-  bool addEvents(Queue<Result> events) {
+  bool update(Queue<Result> events, bool isDone) {
     while (_eventsToSkip > 0) {
-      if (events.isEmpty) return false;
+      if (events.isEmpty) {
+        if (isDone) break;
+        return false;
+      }
       _eventsToSkip--;
+
       var event = events.removeFirst();
       if (event.isError) {
         event.complete(_completer);
         return true;
       }
     }
-    _completer.complete(0);
-    return true;
-  }
-
-  void close(Queue<Result> events) {
     _completer.complete(_eventsToSkip);
+    return true;
   }
 }
 
@@ -481,9 +531,13 @@
   /// The future completed when the correct number of events have been captured.
   Future get future => _completer.future;
 
-  bool addEvents(Queue<Result> events) {
+  bool update(Queue<Result> events, bool isDone) {
     while (_list.length < _eventsToTake) {
-      if (events.isEmpty) return false;
+      if (events.isEmpty) {
+        if (isDone) break;
+        return false;
+      }
+
       var result = events.removeFirst();
       if (result.isError) {
         result.complete(_completer);
@@ -494,10 +548,6 @@
     _completer.complete(_list);
     return true;
   }
-
-  void close(Queue<Result> events) {
-    _completer.complete(_list);
-  }
 }
 
 /// Request for a [StreamQueue.cancel] call.
@@ -520,22 +570,14 @@
   /// The future completed when the cancel request is completed.
   Future get future => _completer.future;
 
-  bool addEvents(Queue<Result> events) {
-    _shutdown();
-    return true;
-  }
-
-  void close(_) {
-    _shutdown();
-  }
-
-  void _shutdown() {
+  bool update(Queue<Result> events, bool isDone) {
     if (_streamQueue._isDone) {
       _completer.complete();
     } else {
       _streamQueue._ensureListening();
-      _completer.complete(_streamQueue._dispose().cancel());
+      _completer.complete(_streamQueue._extractStream().listen(null).cancel());
     }
+    return true;
   }
 }
 
@@ -559,21 +601,12 @@
   /// The stream which will contain the remaining events of [_streamQueue].
   Stream<T> get stream => _completer.stream;
 
-  bool addEvents(Queue<Result> events) {
-    _completeStream(events);
-    return true;
-  }
-
-  void close(Queue<Result> events) {
-    _completeStream(events);
-  }
-
-  void _completeStream(Queue<Result> events) {
+  bool update(Queue<Result> events, bool isDone) {
     if (events.isEmpty) {
       if (_streamQueue._isDone) {
         _completer.setEmpty();
       } else {
-        _completer.setSourceStream(_getRestStream());
+        _completer.setSourceStream(_streamQueue._extractStream());
       }
     } else {
       // There are prefetched events which needs to be added before the
@@ -582,26 +615,11 @@
       for (var event in events) {
         event.addTo(controller);
       }
-      controller.addStream(_getRestStream(), cancelOnError: false)
+      controller.addStream(_streamQueue._extractStream(), cancelOnError: false)
                 .whenComplete(controller.close);
       _completer.setSourceStream(controller.stream);
     }
-  }
-
-  /// Create a stream from the rest of [_streamQueue]'s subscription.
-  Stream _getRestStream() {
-    if (_streamQueue._isDone) {
-      var controller = new StreamController<T>()..close();
-      return controller.stream;
-      // TODO(lrn). Use the following when 1.11 is released.
-      // return new Stream<T>.empty();
-    }
-    if (_streamQueue._subscription == null) {
-      return _streamQueue._sourceStream;
-    }
-    var subscription = _streamQueue._dispose();
-    subscription.resume();
-    return new SubscriptionStream<T>(subscription);
+    return true;
   }
 }
 
@@ -616,15 +634,15 @@
 
   Future<bool> get future => _completer.future;
 
-  bool addEvents(Queue<Result> events) {
+  bool update(Queue<Result> events, bool isDone) {
     if (events.isNotEmpty) {
       _completer.complete(true);
       return true;
     }
+    if (isDone) {
+      _completer.complete(false);
+      return true;
+    }
     return false;
   }
-
-  void close(_) {
-    _completer.complete(false);
-  }
 }
diff --git a/packages/async/pubspec.yaml b/packages/async/pubspec.yaml
index 84b8de5..91d752d 100644
--- a/packages/async/pubspec.yaml
+++ b/packages/async/pubspec.yaml
@@ -1,9 +1,10 @@
 name: async
-version: 1.3.0
+version: 1.4.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
 dev_dependencies:
+  fake_async: "^0.1.2"
   stack_trace: "^1.0.0"
   test: "^0.12.0"
 environment:
diff --git a/packages/async/test/async_memoizer_test.dart b/packages/async/test/async_memoizer_test.dart
index 3289aa9..b8ca38a 100644
--- a/packages/async/test/async_memoizer_test.dart
+++ b/packages/async/test/async_memoizer_test.dart
@@ -21,16 +21,19 @@
   });
 
   test("forwards the return value from the function", () async {
+    expect(cache.future, completion(equals("value")));
     expect(cache.runOnce(() => "value"), completion(equals("value")));
     expect(cache.runOnce(() {}), completion(equals("value")));
   });
 
   test("forwards the return value from an async function", () async {
+    expect(cache.future, completion(equals("value")));
     expect(cache.runOnce(() async => "value"), completion(equals("value")));
     expect(cache.runOnce(() {}), completion(equals("value")));
   });
 
   test("forwards the error from an async function", () async {
+    expect(cache.future, throwsA("error"));
     expect(cache.runOnce(() async => throw "error"), throwsA("error"));
     expect(cache.runOnce(() {}), throwsA("error"));
   });
diff --git a/packages/async/test/cancelable_operation_test.dart b/packages/async/test/cancelable_operation_test.dart
new file mode 100644
index 0000000..189c073
--- /dev/null
+++ b/packages/async/test/cancelable_operation_test.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:async/async.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+  group("without being canceled", () {
+    var completer;
+    setUp(() {
+      completer = new CancelableCompleter(
+          onCancel: expectAsync(() {}, count: 0));
+    });
+
+    test("sends values to the future", () {
+      expect(completer.operation.value, completion(equals(1)));
+      expect(completer.isCompleted, isFalse);
+      completer.complete(1);
+      expect(completer.isCompleted, isTrue);
+    });
+
+    test("sends errors to the future", () {
+      expect(completer.operation.value, throwsA("error"));
+      expect(completer.isCompleted, isFalse);
+      completer.completeError("error");
+      expect(completer.isCompleted, isTrue);
+    });
+
+    test("sends values in a future to the future", () {
+      expect(completer.operation.value, completion(equals(1)));
+      expect(completer.isCompleted, isFalse);
+      completer.complete(new Future.value(1));
+      expect(completer.isCompleted, isTrue);
+    });
+
+    test("sends errors in a future to the future", () {
+      expect(completer.operation.value, throwsA("error"));
+      expect(completer.isCompleted, isFalse);
+      completer.complete(new Future.error("error"));
+      expect(completer.isCompleted, isTrue);
+    });
+
+    group("throws a StateError if completed", () {
+      test("successfully twice", () {
+        completer.complete(1);
+        expect(() => completer.complete(1), throwsStateError);
+      });
+
+      test("successfully then unsuccessfully", () {
+        completer.complete(1);
+        expect(() => completer.completeError("error"), throwsStateError);
+      });
+
+      test("unsuccessfully twice", () {
+        expect(completer.operation.value, throwsA("error"));
+        completer.completeError("error");
+        expect(() => completer.completeError("error"), throwsStateError);
+      });
+
+      test("successfully then with a future", () {
+        completer.complete(1);
+        expect(() => completer.complete(new Completer().future),
+            throwsStateError);
+      });
+
+      test("with a future then successfully", () {
+        completer.complete(new Completer().future);
+        expect(() => completer.complete(1), throwsStateError);
+      });
+
+      test("with a future twice", () {
+        completer.complete(new Completer().future);
+        expect(() => completer.complete(new Completer().future),
+            throwsStateError);
+      });
+    });
+
+    group("CancelableOperation.fromFuture", () {
+      test("forwards values", () {
+        var operation = new CancelableOperation.fromFuture(new Future.value(1));
+        expect(operation.value, completion(equals(1)));
+      });
+
+      test("forwards errors", () {
+        var operation = new CancelableOperation.fromFuture(
+            new Future.error("error"));
+        expect(operation.value, throwsA("error"));
+      });
+    });
+  });
+
+  group("when canceled", () {
+    test("causes the future never to fire", () async {
+      var completer = new CancelableCompleter();
+      completer.operation.value.whenComplete(expectAsync(() {}, count: 0));
+      completer.operation.cancel();
+
+      // Give the future plenty of time to fire if it's going to.
+      await flushMicrotasks();
+      completer.complete();
+      await flushMicrotasks();
+    });
+
+    test("fires onCancel", () {
+      var canceled = false;
+      var completer;
+      completer = new CancelableCompleter(onCancel: expectAsync(() {
+        expect(completer.isCanceled, isTrue);
+        canceled = true;
+      }));
+
+      expect(canceled, isFalse);
+      expect(completer.isCanceled, isFalse);
+      expect(completer.isCompleted, isFalse);
+      completer.operation.cancel();
+      expect(canceled, isTrue);
+      expect(completer.isCanceled, isTrue);
+      expect(completer.isCompleted, isFalse);
+    });
+
+    test("returns the onCancel future each time cancel is called", () {
+      var completer = new CancelableCompleter(onCancel: expectAsync(() {
+        return new Future.value(1);
+      }));
+      expect(completer.operation.cancel(), completion(equals(1)));
+      expect(completer.operation.cancel(), completion(equals(1)));
+      expect(completer.operation.cancel(), completion(equals(1)));
+    });
+
+    test("returns a future even if onCancel doesn't", () {
+      var completer = new CancelableCompleter(onCancel: expectAsync(() {}));
+      expect(completer.operation.cancel(), completes);
+    });
+
+    test("doesn't call onCancel if the completer has completed", () {
+      var completer = new CancelableCompleter(
+          onCancel: expectAsync(() {}, count: 0));
+      completer.complete(1);
+      expect(completer.operation.value, completion(equals(1)));
+      expect(completer.operation.cancel(), completes);
+    });
+
+    test("does call onCancel if the completer has completed to an unfired "
+        "Future", () {
+      var completer = new CancelableCompleter(onCancel: expectAsync(() {}));
+      completer.complete(new Completer().future);
+      expect(completer.operation.cancel(), completes);
+    });
+
+    test("doesn't call onCancel if the completer has completed to a fired "
+        "Future", () async {
+      var completer = new CancelableCompleter(
+          onCancel: expectAsync(() {}, count: 0));
+      completer.complete(new Future.value(1));
+      await completer.operation.value;
+      expect(completer.operation.cancel(), completes);
+    });
+
+    test("can be completed once after being canceled", () async {
+      var completer = new CancelableCompleter();
+      completer.operation.value.whenComplete(expectAsync(() {}, count: 0));
+      await completer.operation.cancel();
+      completer.complete(1);
+      expect(() => completer.complete(1), throwsStateError);
+    });
+  });
+
+  group("asStream()", () {
+    test("emits a value and then closes", () {
+      var completer = new CancelableCompleter();
+      expect(completer.operation.asStream().toList(), completion(equals([1])));
+      completer.complete(1);
+    });
+
+    test("emits an error and then closes", () {
+      var completer = new CancelableCompleter();
+      var queue = new StreamQueue(completer.operation.asStream());
+      expect(queue.next, throwsA("error"));
+      expect(queue.hasNext, completion(isFalse));
+      completer.completeError("error");
+    });
+
+    test("cancels the completer when the subscription is canceled", () {
+      var completer = new CancelableCompleter(onCancel: expectAsync(() {}));
+      var sub = completer.operation.asStream()
+          .listen(expectAsync((_) {}, count: 0));
+      completer.operation.value.whenComplete(expectAsync(() {}, count: 0));
+      sub.cancel();
+      expect(completer.isCanceled, isTrue);
+    });
+  });
+}
diff --git a/packages/async/test/restartable_timer_test.dart b/packages/async/test/restartable_timer_test.dart
new file mode 100644
index 0000000..6732b81
--- /dev/null
+++ b/packages/async/test/restartable_timer_test.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:async/async.dart';
+import 'package:fake_async/fake_async.dart';
+import 'package:test/test.dart';
+
+main() {
+  test("runs the callback once the duration has elapsed", () {
+    new FakeAsync().run((async) {
+      var fired = false;
+      var timer = new RestartableTimer(new Duration(seconds: 5), () {
+        fired = true;
+      });
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+
+      async.elapse(new Duration(seconds: 1));
+      expect(fired, isTrue);
+    });
+  });
+
+  test("doesn't run the callback if the timer is canceled", () {
+    new FakeAsync().run((async) {
+      var fired = false;
+      var timer = new RestartableTimer(new Duration(seconds: 5), () {
+        fired = true;
+      });
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+      timer.cancel();
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+    });
+  });
+
+  test("resets the duration if the timer is reset before it fires", () {
+    new FakeAsync().run((async) {
+      var fired = false;
+      var timer = new RestartableTimer(new Duration(seconds: 5), () {
+        fired = true;
+      });
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+      timer.reset();
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+
+      async.elapse(new Duration(seconds: 1));
+      expect(fired, isTrue);
+    });
+  });
+
+  test("re-runs the callback if the timer is reset after firing", () {
+    new FakeAsync().run((async) {
+      var fired = 0;
+      var timer = new RestartableTimer(new Duration(seconds: 5), () {
+        fired++;
+      });
+
+      async.elapse(new Duration(seconds: 5));
+      expect(fired, equals(1));
+      timer.reset();
+
+      async.elapse(new Duration(seconds: 5));
+      expect(fired, equals(2));
+      timer.reset();
+
+      async.elapse(new Duration(seconds: 5));
+      expect(fired, equals(3));
+    });
+  });
+
+  test("runs the callback if the timer is reset after being canceled", () {
+    new FakeAsync().run((async) {
+      var fired = false;
+      var timer = new RestartableTimer(new Duration(seconds: 5), () {
+        fired = true;
+      });
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+      timer.cancel();
+
+      async.elapse(new Duration(seconds: 4));
+      expect(fired, isFalse);
+      timer.reset();
+
+      async.elapse(new Duration(seconds: 5));
+      expect(fired, isTrue);
+    });
+  });
+
+  test("only runs the callback once if the timer isn't reset", () {
+    new FakeAsync().run((async) {
+      var timer = new RestartableTimer(
+          new Duration(seconds: 5),
+          expectAsync(() {}, count: 1));
+      async.elapse(new Duration(seconds: 10));
+    });
+  });
+}
diff --git a/packages/async/test/subscription_stream_test.dart b/packages/async/test/subscription_stream_test.dart
index 03f0ddd..0d1870b 100644
--- a/packages/async/test/subscription_stream_test.dart
+++ b/packages/async/test/subscription_stream_test.dart
@@ -73,8 +73,11 @@
     for (var sourceCancels in [false, true]) {
       group("${sourceCancels ? "yes" : "no"}:", () {
         var subscriptionStream;
+        var onCancel;  // Completes if source stream is canceled before done.
         setUp(() {
-          var source = createErrorStream();
+          var cancelCompleter = new Completer();
+          var source = createErrorStream(cancelCompleter);
+          onCancel = cancelCompleter.future;
           var sourceSubscription = source.listen(null,
                                                  cancelOnError: sourceCancels);
           subscriptionStream = new SubscriptionStream<int>(sourceSubscription);
@@ -89,9 +92,12 @@
                                     cancelOnError: false);
           var expected = [1, 2, "To err is divine!"];
           if (sourceCancels) {
-            var timeout = done.future.timeout(const Duration(milliseconds: 5),
-                                              onTimeout: () => true);
-            expect(await timeout, true);
+            await onCancel;
+            // And [done] won't complete at all.
+            bool isDone = false;
+            done.future.then((_) { isDone = true; });
+            await new Future.delayed(const Duration(milliseconds: 5));
+            expect(isDone, false);
           } else {
             expected.add(4);
             await done.future;
@@ -155,20 +161,25 @@
   yield 4;
 }
 
-Stream<int> createErrorStream() {
-  StreamController controller = new StreamController<int>();
-  () async {
-    controller.add(1);
+Stream<int> createErrorStream([Completer onCancel]) async* {
+  bool canceled = true;
+  try {
+    yield 1;
     await flushMicrotasks();
-    controller.add(2);
+    yield 2;
     await flushMicrotasks();
-    controller.addError("To err is divine!");
+    yield* new Future.error("To err is divine!").asStream();
     await flushMicrotasks();
-    controller.add(4);
+    yield 4;
     await flushMicrotasks();
-    controller.close();
-  }();
-  return controller.stream;
+    canceled = false;
+  } finally {
+    // Completes before the "done", but should be after all events.
+    if (canceled && onCancel != null) {
+      await flushMicrotasks();
+      onCancel.complete();
+    }
+  }
 }
 
 Stream<int> createLongStream() async* {
diff --git a/packages/charted/lib/charts/behaviors/axis_label_tooltip.dart b/packages/charted/lib/charts/behaviors/axis_label_tooltip.dart
index 6361a4e..092db6b 100644
--- a/packages/charted/lib/charts/behaviors/axis_label_tooltip.dart
+++ b/packages/charted/lib/charts/behaviors/axis_label_tooltip.dart
@@ -38,10 +38,9 @@
   void _subscribe() {
     var elements = _area.host.querySelectorAll(_AXIS_SELECTOR);
     _disposer.dispose();
-    _disposer.addAll(
-        elements.map((x) => x.onMouseOver.listen(_handleMouseOver)));
-    _disposer.addAll(
-        elements.map((x) => x.onMouseOut.listen(_handleMouseOut)));
+    _disposer
+        .addAll(elements.map((x) => x.onMouseOver.listen(_handleMouseOver)));
+    _disposer.addAll(elements.map((x) => x.onMouseOut.listen(_handleMouseOut)));
   }
 
   void _handleMouseOver(MouseEvent e) {
@@ -51,10 +50,8 @@
     ensureRenderAreaRect();
 
     _tooltipRoot.text = target.dataset['detail'];
-    var position = computeTooltipPosition(
-        target.getBoundingClientRect(),
-        _tooltipRoot.getBoundingClientRect(),
-        _renderAreaRect);
+    var position = computeTooltipPosition(target.getBoundingClientRect(),
+        _tooltipRoot.getBoundingClientRect(), _renderAreaRect);
 
     _tooltipRoot.style
       ..left = '${position.x}px'
@@ -94,12 +91,13 @@
     _renderAreaRect = new math.Rectangle(
         _hostAreaRect.left + layout.chartArea.x + layout.renderArea.x,
         _hostAreaRect.top + layout.chartArea.y + layout.renderArea.y,
-        layout.renderArea.width, layout.renderArea.height);
+        layout.renderArea.width,
+        layout.renderArea.height);
   }
 
   /// Computes the ideal tooltip position based on orientation.
-  math.Point computeTooltipPosition(math.Rectangle label,
-      math.Rectangle tooltip, math.Rectangle renderArea) {
+  math.Point computeTooltipPosition(
+      math.Rectangle label, math.Rectangle tooltip, math.Rectangle renderArea) {
     var x = label.left + (label.width - tooltip.width) / 2,
         y = label.top + (label.height - tooltip.height) / 2;
 
diff --git a/packages/charted/lib/charts/behaviors/chart_tooltip.dart b/packages/charted/lib/charts/behaviors/chart_tooltip.dart
index f588d80..083d0f8 100644
--- a/packages/charted/lib/charts/behaviors/chart_tooltip.dart
+++ b/packages/charted/lib/charts/behaviors/chart_tooltip.dart
@@ -27,8 +27,8 @@
   /// Constructs the tooltip.
   /// If [showDimensionValue] is set, displays the dimension value as title.
   /// If [showMeasureTotal] is set, displays the total value.
-  ChartTooltip({
-      this.showSelectedMeasure: false,
+  ChartTooltip(
+      {this.showSelectedMeasure: false,
       this.showDimensionValue: false,
       this.showMeasureTotal: false,
       this.orientation: ORIENTATION_RIGHT});
@@ -38,8 +38,8 @@
     _area = area;
     _state = area.state;
     _disposer.addAll([
-        area.onValueMouseOver.listen(show),
-        area.onValueMouseOut.listen(hide)
+      area.onValueMouseOver.listen(show),
+      area.onValueMouseOut.listen(hide)
     ]);
 
     // Tooltip requires host to be position: relative.
@@ -92,8 +92,8 @@
     var activeMeasures = [];
     if (showSelectedMeasure) {
       activeMeasures.addAll(_state.selection);
-      activeMeasures.add(_state.preview != null ? _state.preview :
-          _state.hovered.first);
+      activeMeasures
+          .add(_state.preview != null ? _state.preview : _state.hovered.first);
       if (activeMeasures.isEmpty) {
         for (var series in _area.config.series) {
           activeMeasures.addAll(series.measures);
@@ -105,35 +105,33 @@
     var data = (showSelectedMeasure) ? activeMeasures : e.series.measures;
 
     // Create the tooltip items base on the number of measures in the series.
-    var items = _tooltipRoot.selectAll('.tooltip-item').
-        data(data);
+    var items = _tooltipRoot.selectAll('.tooltip-item').data(data);
     items.enter.append('div')
-        ..classed('tooltip-item')
-        ..classedWithCallback('active', (d, i, c) =>
-            !showSelectedMeasure && (d == e.column));
+      ..classed('tooltip-item')
+      ..classedWithCallback(
+          'active', (d, i, c) => !showSelectedMeasure && (d == e.column));
 
     // Display the label for the currently active series.
     var tooltipItems = _tooltipRoot.selectAll('.tooltip-item');
     tooltipItems.append('div')
-        ..classed('tooltip-item-label')
-        ..textWithCallback((d, i, c) => _area.data.columns.
-            elementAt((showSelectedMeasure) ? d :
-            e.series.measures.elementAt(i)).label);
+      ..classed('tooltip-item-label')
+      ..textWithCallback((d, i, c) => _area.data.columns
+          .elementAt((showSelectedMeasure) ? d : e.series.measures.elementAt(i))
+          .label);
 
     // Display the value of the currently active series
     tooltipItems.append('div')
       ..classed('tooltip-item-value')
-      ..styleWithCallback('color', (d, i, c) =>
-          _area.theme.getColorForKey(d))
+      ..styleWithCallback('color', (d, i, c) => _area.theme.getColorForKey(d))
       ..textWithCallback((d, i, c) {
-      var formatter = _getFormatterForColumn(d),
-          value = _area.data.rows.elementAt(e.row).elementAt(d);
-      return (formatter != null) ? formatter(value) : value.toString();
-    });
+        var formatter = _getFormatterForColumn(d),
+            value = _area.data.rows.elementAt(e.row).elementAt(d);
+        return (formatter != null) ? formatter(value) : value.toString();
+      });
 
     math.Point position = computeTooltipPosition(
         new math.Point(e.chartX, e.chartY),
-            _tooltipRoot.first.getBoundingClientRect());
+        _tooltipRoot.first.getBoundingClientRect());
 
     // Set position of the tooltip and display it.
     _tooltipRoot
@@ -143,13 +141,10 @@
   }
 
   static String switchPositionDirection(String direction) =>
-      direction == ORIENTATION_LEFT
-          ? ORIENTATION_RIGHT
-          : ORIENTATION_LEFT;
+      direction == ORIENTATION_LEFT ? ORIENTATION_RIGHT : ORIENTATION_LEFT;
 
   /// Computes the ideal tooltip position based on orientation.
-  math.Point computeTooltipPosition(
-      math.Point coord, math.Rectangle rect) {
+  math.Point computeTooltipPosition(math.Point coord, math.Rectangle rect) {
     var x, y, direction;
     direction = _area.config.isRTL && _area.config.switchAxesForRTL
         ? switchPositionDirection(orientation)
@@ -198,4 +193,3 @@
     _tooltipRoot.style('opacity', '0');
   }
 }
-
diff --git a/packages/charted/lib/charts/behaviors/hovercard.dart b/packages/charted/lib/charts/behaviors/hovercard.dart
index f01d2ac..ff62aa7 100644
--- a/packages/charted/lib/charts/behaviors/hovercard.dart
+++ b/packages/charted/lib/charts/behaviors/hovercard.dart
@@ -58,8 +58,14 @@
   bool _showDimensionTitle;
   Iterable<int> _columnsToShow;
 
-  Iterable placementOrder =
-      const['orientation', 'top', 'right', 'bottom', 'left', 'orientation'];
+  Iterable placementOrder = const [
+    'orientation',
+    'top',
+    'right',
+    'bottom',
+    'left',
+    'orientation'
+  ];
   int offset = 20;
 
   ChartArea _area;
@@ -68,8 +74,8 @@
 
   Element _hovercardRoot;
 
-  Hovercard({
-      bool isMouseTracking,
+  Hovercard(
+      {bool isMouseTracking,
       bool isMultiValue: false,
       bool showDimensionTitle: false,
       List columnsToShow: const [],
@@ -91,8 +97,8 @@
     // Subscribe to events.
     if (_isMouseTracking) {
       _disposer.addAll([
-          _area.onValueMouseOver.listen(_handleMouseOver),
-          _area.onValueMouseOut.listen(_handleMouseOut)
+        _area.onValueMouseOver.listen(_handleMouseOver),
+        _area.onValueMouseOut.listen(_handleMouseOut)
       ]);
     } else {
       _disposer.add(_state.changes.listen(_handleStateChange));
@@ -206,12 +212,12 @@
     var rowData = area.data.rows.elementAt(row),
         measurePosition = 0,
         isNegative = false,
-        dimensionPosition = dimensionScale.scale(
-            rowData.elementAt(dimensionCol)) + dimensionCenterOffset;
+        dimensionPosition = dimensionScale
+                .scale(rowData.elementAt(dimensionCol)) +
+            dimensionCenterOffset;
 
     if (_isMultiValue) {
-      var max = SMALL_INT_MIN,
-          min = SMALL_INT_MAX;
+      var max = SMALL_INT_MIN, min = SMALL_INT_MAX;
       area.config.series.forEach((ChartSeries series) {
         CartesianRenderer renderer = series.renderer;
         Extent extent = renderer.extentForRow(rowData);
@@ -227,24 +233,26 @@
     }
 
     if (area.config.isLeftAxisPrimary) {
-      _positionAtPoint(measurePosition, dimensionPosition,
-          0, dimensionOffset, isNegative, true);
+      _positionAtPoint(measurePosition, dimensionPosition, 0, dimensionOffset,
+          isNegative, true);
     } else {
-      _positionAtPoint(dimensionPosition, measurePosition,
-          dimensionOffset, 0, isNegative, false);
+      _positionAtPoint(dimensionPosition, measurePosition, dimensionOffset, 0,
+          isNegative, false);
     }
   }
 
-  void _positionAtPoint(num x, num y,
-      num xBand, num yBand, bool negative, [bool isLeftPrimary = false]) {
+  void _positionAtPoint(num x, num y, num xBand, num yBand, bool negative,
+      [bool isLeftPrimary = false]) {
     var rect = _hovercardRoot.getBoundingClientRect(),
         width = rect.width,
         height = rect.height,
-        scaleToHostY =
-            (_area.theme.padding != null ? _area.theme.padding.top : 0) +
+        scaleToHostY = (_area.theme.padding != null
+                ? _area.theme.padding.top
+                : 0) +
             (_area.layout.renderArea.y),
-        scaleToHostX =
-            (_area.theme.padding != null ? _area.theme.padding.start: 0) +
+        scaleToHostX = (_area.theme.padding != null
+                ? _area.theme.padding.start
+                : 0) +
             (_area.layout.renderArea.x),
         renderAreaHeight = _area.layout.renderArea.height,
         renderAreaWidth = _area.layout.renderArea.width;
@@ -280,8 +288,10 @@
 
       // Check if the popup is contained in the RenderArea.
       // If not, try other placements.
-      if (top > 0 && left > 0 &&
-          top + height < renderAreaHeight && left + width < renderAreaWidth) {
+      if (top > 0 &&
+          left > 0 &&
+          top + height < renderAreaHeight &&
+          left + width < renderAreaWidth) {
         break;
       }
     }
@@ -300,7 +310,7 @@
       element.append(titleElement);
     }
 
-    var measureVals =  _getMeasuresData(column, row);
+    var measureVals = _getMeasuresData(column, row);
     measureVals.forEach((ChartLegendItem item) {
       var labelElement = new Element.div()
             ..className = 'hovercard-measure-label'
@@ -349,7 +359,7 @@
 
   ChartLegendItem _createHovercardItem(int column, int row) {
     var rowData = _area.data.rows.elementAt(row),
-        columns =  _area.data.columns,
+        columns = _area.data.columns,
         spec = columns.elementAt(column),
         colorKey = _area.useRowColoring ? row : column,
         formatter = _getFormatterForColumn(column),
@@ -370,16 +380,17 @@
     } else {
       var count = (_area as CartesianArea).useTwoDimensionAxes ? 2 : 1,
           dimensions = _area.config.dimensions.take(count);
-      return dimensions.map(
-          (int c) =>
-              _getFormatterForColumn(c)(rowData.elementAt(c))).join(', ');
+      return dimensions
+          .map((int c) => _getFormatterForColumn(c)(rowData.elementAt(c)))
+          .join(', ');
     }
   }
 
   // TODO: Move this to a common place?
   Scale _getScaleForColumn(int column) {
     var series = _area.config.series.firstWhere(
-        (ChartSeries x) => x.measures.contains(column), orElse: () => null);
+        (ChartSeries x) => x.measures.contains(column),
+        orElse: () => null);
     return series != null
         ? (_area as CartesianArea).measureScales(series).first
         : null;
diff --git a/packages/charted/lib/charts/behaviors/line_marker.dart b/packages/charted/lib/charts/behaviors/line_marker.dart
index f6abd22..3166f3c 100644
--- a/packages/charted/lib/charts/behaviors/line_marker.dart
+++ b/packages/charted/lib/charts/behaviors/line_marker.dart
@@ -11,7 +11,7 @@
 /// A behavior that draws marking lines on the chart.
 class LineMarker implements ChartBehavior {
   /// Position of the line markers.
-  final Map<int,dynamic> positions;
+  final Map<int, dynamic> positions;
 
   /// If true, the markers are drawn above the series
   final bool drawAboveSeries;
@@ -37,8 +37,7 @@
     _area = area;
     _parent = drawAboveSeries ? upper : lower;
     _isLeftAxisPrimary = _area.config.isLeftAxisPrimary;
-    _axesChangeSubscription =
-        _area.onChartAxesUpdated.listen((_) => _update());
+    _axesChangeSubscription = _area.onChartAxesUpdated.listen((_) => _update());
     _update();
   }
 
@@ -53,14 +52,14 @@
     assert(_isDimension(column));
 
     int index;
-    for(index = 0;
-        _area.config.dimensions.elementAt(index) != column; ++index);
+    for (index = 0;
+        _area.config.dimensions.elementAt(index) != column;
+        ++index);
 
     assert(index == 0 || index == 1 && _area.useTwoDimensionAxes);
 
     var dimensionAtBottom =
-            index == 1 && _isLeftAxisPrimary ||
-            index == 0 && !_isLeftAxisPrimary,
+        index == 1 && _isLeftAxisPrimary || index == 0 && !_isLeftAxisPrimary,
         scale = _area.dimensionScales.elementAt(index),
         scaled = scale.scale(positions[column]),
         theme = _area.theme.getDimensionAxisTheme(),
@@ -71,8 +70,7 @@
         top = initial ? bottom : renderAreaRect.y;
 
     if (scale is OrdinalScale) {
-      var band = scale.rangeBand,
-          bandPadding = theme.axisBandInnerPadding;
+      var band = scale.rangeBand, bandPadding = theme.axisBandInnerPadding;
       scaled = scaled - band * bandPadding + _area.theme.defaultStrokeWidth;
       band = band + 2 * (band * bandPadding - _area.theme.defaultStrokeWidth);
       return dimensionAtBottom
@@ -89,10 +87,9 @@
     throw new UnimplementedError('Measure axis markers');
   }
 
-  String _getMarkerPath(int column, bool initial) =>
-      _isDimension(column)
-          ? _pathForDimension(column, initial)
-          : _pathForMeasure(column, initial);
+  String _getMarkerPath(int column, bool initial) => _isDimension(column)
+      ? _pathForDimension(column, initial)
+      : _pathForMeasure(column, initial);
 
   void _update() {
     if (!_area.isReady) return;
@@ -104,11 +101,11 @@
     });
 
     if (animate) {
-      _markers.transition()
+      _markers
+          .transition()
           .attrWithCallback('d', (d, i, e) => _getMarkerPath(d, false));
     }
 
     _markers.exit.remove();
   }
 }
-
diff --git a/packages/charted/lib/charts/cartesian_renderers/bar_chart_renderer.dart b/packages/charted/lib/charts/cartesian_renderers/bar_chart_renderer.dart
index cc55c2d..74e93ca 100644
--- a/packages/charted/lib/charts/cartesian_renderers/bar_chart_renderer.dart
+++ b/packages/charted/lib/charts/cartesian_renderers/bar_chart_renderer.dart
@@ -11,7 +11,7 @@
 class BarChartRenderer extends CartesianRendererBase {
   static const RADIUS = 2;
 
-  final Iterable<int> dimensionsUsingBand = const[0];
+  final Iterable<int> dimensionsUsingBand = const [0];
   final bool alwaysAnimate;
 
   @override
@@ -38,12 +38,12 @@
         dimensionScale = area.dimensionScales.first;
 
     var rows = new List()
-      ..addAll(area.data.rows.map((e) =>
-          new List.generate(
-              measuresCount, (i) => e[series.measures.elementAt(i)])));
+      ..addAll(area.data.rows.map((e) => new List.generate(
+          measuresCount, (i) => e[series.measures.elementAt(i)])));
 
-    var dimensionVals = area.data.rows.map(
-        (row) => row.elementAt(area.config.dimensions.first)).toList();
+    var dimensionVals = area.data.rows
+        .map((row) => row.elementAt(area.config.dimensions.first))
+        .toList();
 
     var bars = new OrdinalScale()
       ..domain = new Range(series.measures.length).toList()
@@ -56,32 +56,37 @@
 
     groups.enter.append('g')
       ..classed('bar-rdr-rowgroup')
-      ..attrWithCallback('transform', (d, i, c) => verticalBars ?
-          'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
-          'translate(0, ${dimensionScale.scale(dimensionVals[i])})');
+      ..attrWithCallback(
+          'transform',
+          (d, i, c) => verticalBars
+              ? 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)'
+              : 'translate(0, ${dimensionScale.scale(dimensionVals[i])})');
     groups.attrWithCallback('data-row', (d, i, e) => i);
     groups.exit.remove();
 
     if (animateBarGroups) {
       groups.transition()
-        ..attrWithCallback('transform', (d, i, c) => verticalBars ?
-            'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
-            'translate(0, ${dimensionScale.scale(dimensionVals[i])})')
+        ..attrWithCallback(
+            'transform',
+            (d, i, c) => verticalBars
+                ? 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)'
+                : 'translate(0, ${dimensionScale.scale(dimensionVals[i])})')
         ..duration(theme.transitionDurationMilliseconds);
     }
 
     // TODO: Test interactions between stroke width and bar width.
 
     var barWidth = bars.rangeBand.abs() -
-            theme.defaultSeparatorWidth - theme.defaultStrokeWidth,
+            theme.defaultSeparatorWidth -
+            theme.defaultStrokeWidth,
         strokeWidth = theme.defaultStrokeWidth,
         strokeWidthOffset = strokeWidth ~/ 2;
 
     // Create and update the bars
     // Avoids animation on first render unless alwaysAnimate is set to true.
 
-    var bar = groups.selectAll('.bar-rdr-bar').dataWithCallback(
-            (d, i, c) => rows[i]),
+    var bar =
+        groups.selectAll('.bar-rdr-bar').dataWithCallback((d, i, c) => rows[i]),
         scaled0 = measureScale.scale(0).round();
 
     var getBarLength = (d) {
@@ -105,42 +110,43 @@
         return fn(
             bars.scale(i).toInt() + strokeWidthOffset,
             animate ? rect.height : getBarPos(d),
-            barWidth, animate ? 0 : getBarLength(d), RADIUS);
+            barWidth,
+            animate ? 0 : getBarLength(d),
+            RADIUS);
       } else {
-        var fn = d > 0 ? rightRoundedRect  : leftRoundedRect;
-        return fn(
-            getBarPos(d), bars.scale(i).toInt() + strokeWidthOffset,
+        var fn = d > 0 ? rightRoundedRect : leftRoundedRect;
+        return fn(getBarPos(d), bars.scale(i).toInt() + strokeWidthOffset,
             animate ? 0 : getBarLength(d), barWidth, RADIUS);
       }
     };
 
     bar.enter.appendWithCallback((d, i, e) {
-        var rect = Namespace.createChildElement('path', e),
-            measure = series.measures.elementAt(i),
-            row = int.parse(e.dataset['row']),
-            color = colorForValue(measure, row),
-            filter = filterForValue(measure, row),
-            style = stylesForValue(measure, row);
+      var rect = Namespace.createChildElement('path', e),
+          measure = series.measures.elementAt(i),
+          row = int.parse(e.dataset['row']),
+          color = colorForValue(measure, row),
+          filter = filterForValue(measure, row),
+          style = stylesForValue(measure, row);
 
-        if (!isNullOrEmpty(style)) {
-          rect.classes.addAll(style);
-        }
-        rect.classes.add('bar-rdr-bar');
+      if (!isNullOrEmpty(style)) {
+        rect.classes.addAll(style);
+      }
+      rect.classes.add('bar-rdr-bar');
 
-        rect.attributes
-          ..['d'] = buildPath(d, i, animateBarGroups)
-          ..['stroke-width'] = '${strokeWidth}px'
-          ..['fill'] = color
-          ..['stroke'] = color;
+      rect.attributes
+        ..['d'] = buildPath(d, i, animateBarGroups)
+        ..['stroke-width'] = '${strokeWidth}px'
+        ..['fill'] = color
+        ..['stroke'] = color;
 
-        if (!isNullOrEmpty(filter)) {
-          rect.attributes['filter'] = filter;
-        }
-        if (!animateBarGroups) {
-          rect.attributes['data-column'] = '$measure';
-        }
-        return rect;
-      })
+      if (!isNullOrEmpty(filter)) {
+        rect.attributes['filter'] = filter;
+      }
+      if (!animateBarGroups) {
+        rect.attributes['data-column'] = '$measure';
+      }
+      return rect;
+    })
       ..on('click', (d, i, e) => _event(mouseClickController, d, i, e))
       ..on('mouseover', (d, i, e) => _event(mouseOverController, d, i, e))
       ..on('mouseout', (d, i, e) => _event(mouseOutController, d, i, e));
@@ -167,8 +173,7 @@
       });
 
       bar.transition()
-        ..attrWithCallback('d',
-            (d, i, e) => buildPath(d, i, false));
+        ..attrWithCallback('d', (d, i, e) => buildPath(d, i, false));
     }
 
     bar.exit.remove();
@@ -184,8 +189,9 @@
   double get bandInnerPadding {
     assert(series != null && area != null);
     var measuresCount = series.measures.length;
-    return measuresCount > 2 ? 1 - (measuresCount / (measuresCount + 1)) :
-        area.theme.getDimensionAxisTheme().axisBandInnerPadding;
+    return measuresCount > 2
+        ? 1 - (measuresCount / (measuresCount + 1))
+        : area.theme.getDimensionAxisTheme().axisBandInnerPadding;
   }
 
   @override
@@ -199,12 +205,12 @@
     var groups = host.querySelectorAll('.bar-rdr-rowgroup');
     if (groups == null || groups.isEmpty) return;
 
-    for(int i = 0, len = groups.length; i < len; ++i) {
+    for (int i = 0, len = groups.length; i < len; ++i) {
       var group = groups.elementAt(i),
           bars = group.querySelectorAll('.bar-rdr-bar'),
           row = int.parse(group.dataset['row']);
 
-      for(int j = 0, barsCount = bars.length; j < barsCount; ++j) {
+      for (int j = 0, barsCount = bars.length; j < barsCount; ++j) {
         var bar = bars.elementAt(j),
             column = int.parse(bar.dataset['column']),
             color = colorForValue(column, row),
@@ -228,8 +234,7 @@
     if (controller == null) return;
     var rowStr = e.parent.dataset['row'];
     var row = rowStr != null ? int.parse(rowStr) : null;
-    controller.add(
-        new DefaultChartEventImpl(scope.event, area,
-            series, row, series.measures.elementAt(index), data));
+    controller.add(new DefaultChartEventImpl(scope.event, area, series, row,
+        series.measures.elementAt(index), data));
   }
 }
diff --git a/packages/charted/lib/charts/cartesian_renderers/bubble_chart_renderer.dart b/packages/charted/lib/charts/cartesian_renderers/bubble_chart_renderer.dart
index 7c285cc..b05dd81 100644
--- a/packages/charted/lib/charts/cartesian_renderers/bubble_chart_renderer.dart
+++ b/packages/charted/lib/charts/cartesian_renderers/bubble_chart_renderer.dart
@@ -1,15 +1,15 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
 class BubbleChartRenderer extends CartesianRendererBase {
-  final Iterable<int> dimensionsUsingBand = const[];
+  final Iterable<int> dimensionsUsingBand = const [];
   final double maxBubbleRadius;
   final bool alwaysAnimate;
 
@@ -20,13 +20,9 @@
   @override
   final String name = "bubble-rdr";
 
-  BubbleChartRenderer({
-      this.maxBubbleRadius: 20.0,
-      this.alwaysAnimate: false});
+  BubbleChartRenderer({this.maxBubbleRadius: 20.0, this.alwaysAnimate: false});
 
-  /*
-   * BubbleChart needs two dimension axes.
-   */
+  /// BubbleChart needs two dimension axes.
   @override
   bool prepare(ChartArea area, ChartSeries series) {
     _ensureAreaAndSeries(area, series);
@@ -50,7 +46,7 @@
         yDimensionScale = area.dimensionScales.last,
         theme = area.theme,
         bubbleRadiusFactor =
-            maxBubbleRadius / min([geometry.width, geometry.height]);
+        maxBubbleRadius / min([geometry.width, geometry.height]);
 
     String color(i) => theme.getColorForKey(series.measures.elementAt(i));
 
@@ -79,8 +75,8 @@
     });
     group.exit.remove();
 
-    var measures = group.selectAll('.bubble').dataWithCallback(
-        (d, i, e) => columns[i]);
+    var measures =
+        group.selectAll('.bubble').dataWithCallback((d, i, e) => columns[i]);
 
     measures.enter.append('circle')..classed('bubble');
     measures.each((d, i, e) {
@@ -111,9 +107,7 @@
   @override
   Extent get extent {
     assert(series != null && area != null);
-    var rows = area.data.rows,
-        max = rows[0][series.measures.first],
-        min = max;
+    var rows = area.data.rows, max = rows[0][series.measures.first], min = max;
 
     rows.forEach((row) {
       series.measures.forEach((idx) {
@@ -129,21 +123,19 @@
     var groups = host.querySelectorAll('.bar-rdr-rowgroup');
     if (groups == null || groups.isEmpty) return;
 
-    for(int i = 0, len = groups.length; i < len; ++i) {
+    for (int i = 0, len = groups.length; i < len; ++i) {
       var group = groups.elementAt(i),
           bars = group.querySelectorAll('.bar-rdr-bar'),
           row = int.parse(group.dataset['row']);
 
-      for(int j = 0, barsCount = bars.length; j < barsCount; ++j) {
+      for (int j = 0, barsCount = bars.length; j < barsCount; ++j) {
         var bar = bars.elementAt(j),
             column = int.parse(bar.dataset['column']),
             color = colorForValue(column, row);
 
         bar.classes.removeAll(ChartState.VALUE_CLASS_NAMES);
         bar.classes.addAll(stylesForValue(column, row));
-        bar.style
-          ..setProperty('fill', color)
-          ..setProperty('stroke', color);
+        bar.style..setProperty('fill', color)..setProperty('stroke', color);
       }
     }
   }
@@ -152,7 +144,7 @@
     if (controller == null) return;
     var rowStr = e.parent.dataset['row'];
     var row = rowStr != null ? int.parse(rowStr) : null;
-    controller.add(
-        new DefaultChartEventImpl(_scope.event, area, series, row, index, data));
+    controller.add(new DefaultChartEventImpl(
+        _scope.event, area, series, row, index, data));
   }
 }
diff --git a/packages/charted/lib/charts/cartesian_renderers/cartesian_base_renderer.dart b/packages/charted/lib/charts/cartesian_renderers/cartesian_base_renderer.dart
index 08d8917..96873bd 100644
--- a/packages/charted/lib/charts/cartesian_renderers/cartesian_base_renderer.dart
+++ b/packages/charted/lib/charts/cartesian_renderers/cartesian_base_renderer.dart
@@ -1,10 +1,10 @@
-/**
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
@@ -20,9 +20,9 @@
   List<int> _columnStateCache;
   List<Iterable<String>> _columnStylesCache;
 
-  final _valueColorCache = new Map<int,String>();
-  final _valueFilterCache = new Map<int,String>();
-  final _valueStylesCache = new Map<int,Iterable<String>>();
+  final _valueColorCache = new Map<int, String>();
+  final _valueFilterCache = new Map<int, String>();
+  final _valueStylesCache = new Map<int, Iterable<String>>();
 
   Element host;
   Selection root;
@@ -103,13 +103,10 @@
   @override
   Extent extentForRow(Iterable row) {
     assert(series != null && area != null);
-    var measures = series.measures,
-        max = SMALL_INT_MIN,
-        min = SMALL_INT_MAX;
+    var measures = series.measures, max = SMALL_INT_MIN, min = SMALL_INT_MAX;
 
-    for (int i = 0, len = measures.length;  i < len; ++i) {
-      var measure = measures.elementAt(i),
-          value = row.elementAt(measure);
+    for (int i = 0, len = measures.length; i < len; ++i) {
+      var measure = measures.elementAt(i), value = row.elementAt(measure);
       if (value != null && value.isFinite) {
         if (value > max) {
           max = value;
@@ -183,14 +180,13 @@
   Iterable<String> stylesForColumn(int column) {
     if (_columnStylesCache[column] == null) {
       if (state == null || area.useRowColoring) {
-        _columnStylesCache[column] = const[];
+        _columnStylesCache[column] = const [];
       } else {
-        var styles = [],
-            flags = _columnStateCache[column];
+        var styles = [], flags = _columnStateCache[column];
 
         if (flags & ChartState.COL_SELECTED != 0) {
           styles.add(ChartState.COL_SELECTED_CLASS);
-        } else if (flags & ChartState.COL_UNSELECTED != 0){
+        } else if (flags & ChartState.COL_UNSELECTED != 0) {
           styles.add(ChartState.COL_UNSELECTED_CLASS);
         }
 
@@ -226,7 +222,7 @@
     var hash = hash2(column, row);
     if (_valueStylesCache[hash] == null) {
       if (state == null) {
-        _valueStylesCache[hash] = const[];
+        _valueStylesCache[hash] = const [];
       } else {
         var styles = stylesForColumn(column).toList();
         if (state.highlights.isNotEmpty) {
@@ -268,8 +264,8 @@
       var flags = _columnStateCache[column];
       if (state.highlights.isNotEmpty) {
         flags |= (state.highlights.any((x) => x.last == row)
-        ? ChartState.VAL_HIGHLIGHTED
-        : ChartState.VAL_UNHIGHLIGHTED);
+            ? ChartState.VAL_HIGHLIGHTED
+            : ChartState.VAL_UNHIGHLIGHTED);
       }
       if (state.hovered != null && state.hovered.last == row) {
         flags |= ChartState.VAL_HOVERED;
diff --git a/packages/charted/lib/charts/cartesian_renderers/line_chart_renderer.dart b/packages/charted/lib/charts/cartesian_renderers/line_chart_renderer.dart
index 0584024..e67fcaa 100644
--- a/packages/charted/lib/charts/cartesian_renderers/line_chart_renderer.dart
+++ b/packages/charted/lib/charts/cartesian_renderers/line_chart_renderer.dart
@@ -1,15 +1,15 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
 class LineChartRenderer extends CartesianRendererBase {
-  final Iterable<int> dimensionsUsingBand = const[];
+  final Iterable<int> dimensionsUsingBand = const [];
   final SubscriptionsDisposer _disposer = new SubscriptionsDisposer();
 
   final bool alwaysAnimate;
@@ -29,16 +29,14 @@
   @override
   final String name = "line-rdr";
 
-  LineChartRenderer({
-      this.alwaysAnimate: false,
+  LineChartRenderer(
+      {this.alwaysAnimate: false,
       this.trackDataPoints: true,
       this.trackOnDimensionAxis: false,
-      this.quantitativeScaleProximity: 5 });
+      this.quantitativeScaleProximity: 5});
 
-  /*
-   * Returns false if the number of dimension axes on the area is 0.
-   * Otherwise, the first dimension scale is used to render the chart.
-   */
+  // Returns false if the number of dimension axes on the area is 0.
+  // Otherwise, the first dimension scale is used to render the chart.
   @override
   bool prepare(ChartArea area, ChartSeries series) {
     _ensureAreaAndSeries(area, series);
@@ -62,8 +60,9 @@
 
     // We only support one dimension axes, so we always use the
     // first dimension.
-    var x = area.data.rows.map(
-        (row) => row.elementAt(area.config.dimensions.first)).toList();
+    var x = area.data.rows
+        .map((row) => row.elementAt(area.config.dimensions.first))
+        .toList();
 
     var rangeBandOffset =
         dimensionScale is OrdinalScale ? dimensionScale.rangeBand / 2 : 0;
@@ -152,15 +151,15 @@
 
     linePoints
       ..each((d, i, e) {
-      var color = colorForColumn(d);
-      e.attributes
-        ..['r'] = '4'
-        ..['stroke'] = color
-        ..['fill'] = color
-        ..['data-column'] = '$d';
+        var color = colorForColumn(d);
+        e.attributes
+          ..['r'] = '4'
+          ..['stroke'] = color
+          ..['fill'] = color
+          ..['data-column'] = '$d';
       })
       ..on('click', _mouseClickHandler)
-      ..on('mousemove', _mouseOverHandler)  // Ensure that we update values
+      ..on('mousemove', _mouseOverHandler) // Ensure that we update values
       ..on('mouseover', _mouseOverHandler)
       ..on('mouseout', _mouseOutHandler);
 
@@ -178,8 +177,7 @@
       var x = _xPositions[row],
           measureVal = area.data.rows.elementAt(row).elementAt(d);
       if (measureVal != null && measureVal.isFinite) {
-        var color = colorForColumn(d),
-            filter = filterForColumn(d);
+        var color = colorForColumn(d), filter = filterForColumn(d);
         e.attributes
           ..['cx'] = '$x'
           ..['cy'] = '${yScale.scale(measureVal)}'
@@ -208,7 +206,7 @@
       ..style('visibility', 'hidden');
   }
 
-  int _getNearestRowIndex(double x) {
+  int _getNearestRowIndex(num x) {
     var lastSmallerValue = 0;
     var chartX = x - area.layout.renderArea.x;
     for (var i = 0; i < _xPositions.length; i++) {
@@ -216,8 +214,9 @@
       if (pos < chartX) {
         lastSmallerValue = pos;
       } else {
-        return i == 0 ? 0 :
-          (chartX - lastSmallerValue <= pos - chartX) ? i - 1 : i;
+        return i == 0
+            ? 0
+            : (chartX - lastSmallerValue <= pos - chartX) ? i - 1 : i;
       }
     }
     return _xPositions.length - 1;
diff --git a/packages/charted/lib/charts/cartesian_renderers/stackedbar_chart_renderer.dart b/packages/charted/lib/charts/cartesian_renderers/stackedbar_chart_renderer.dart
index 396b804..05623ba 100644
--- a/packages/charted/lib/charts/cartesian_renderers/stackedbar_chart_renderer.dart
+++ b/packages/charted/lib/charts/cartesian_renderers/stackedbar_chart_renderer.dart
@@ -11,7 +11,7 @@
 class StackedBarChartRenderer extends CartesianRendererBase {
   static const RADIUS = 2;
 
-  final Iterable<int> dimensionsUsingBand = const[0];
+  final Iterable<int> dimensionsUsingBand = const [0];
   final bool alwaysAnimate;
 
   @override
@@ -41,28 +41,32 @@
         dimensionScale = area.dimensionScales.first;
 
     var rows = new List()
-      ..addAll(area.data.rows.map((e) =>
-          new List.generate(measuresCount,
-              (i) => e.elementAt(series.measures.elementAt(_reverseIdx(i))))));
+      ..addAll(area.data.rows.map((e) => new List.generate(measuresCount,
+          (i) => e.elementAt(series.measures.elementAt(_reverseIdx(i))))));
 
-    var dimensionVals = area.data.rows.map(
-        (row) => row.elementAt(area.config.dimensions.first)).toList();
+    var dimensionVals = area.data.rows
+        .map((row) => row.elementAt(area.config.dimensions.first))
+        .toList();
 
     var groups = root.selectAll('.stack-rdr-rowgroup').data(rows);
     var animateBarGroups = alwaysAnimate || !groups.isEmpty;
     groups.enter.append('g')
       ..classed('stack-rdr-rowgroup')
-      ..attrWithCallback('transform', (d, i, c) => verticalBars ?
-          'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
-          'translate(0, ${dimensionScale.scale(dimensionVals[i])})');
+      ..attrWithCallback(
+          'transform',
+          (d, i, c) => verticalBars
+              ? 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)'
+              : 'translate(0, ${dimensionScale.scale(dimensionVals[i])})');
     groups.attrWithCallback('data-row', (d, i, e) => i);
     groups.exit.remove();
 
     if (animateBarGroups) {
       groups.transition()
-        ..attrWithCallback('transform', (d, i, c) => verticalBars ?
-            'translate(${dimensionScale.scale(dimensionVals[i])}, 0)' :
-            'translate(0, ${dimensionScale.scale(dimensionVals[i])})')
+        ..attrWithCallback(
+            'transform',
+            (d, i, c) => verticalBars
+                ? 'translate(${dimensionScale.scale(dimensionVals[i])}, 0)'
+                : 'translate(0, ${dimensionScale.scale(dimensionVals[i])})')
         ..duration(theme.transitionDurationMilliseconds);
     }
 
@@ -83,15 +87,13 @@
           prevOffsetVal[prevOffsetVal.length - 1] = offsetVal;
         }
       });
-     }
-
+    }
 
     var barWidth = dimensionScale.rangeBand - theme.defaultStrokeWidth;
 
     // Calculate height of each segment in the bar.
     // Uses prevAllZeroHeight and prevOffset to track previous segments
-    var prevAllZeroHeight = true,
-        prevOffset = 0;
+    var prevAllZeroHeight = true, prevOffset = 0;
     var getBarLength = (d, i) {
       if (!verticalBars) return measureScale.scale(d).round();
       var retval = rect.height - measureScale.scale(d).round();
@@ -121,8 +123,7 @@
 
     // Initial "y" position of a bar that is being created.
     // Only used when animateBarGroups is set to true.
-    var ic = 10000000,
-        order = 0;
+    var ic = 10000000, order = 0;
     var getInitialBarPos = (i) {
       var tempY;
       if (i <= ic && i > 0) {
@@ -163,14 +164,15 @@
     var buildPath = (d, int i, Element e, bool animate, int roundIdx) {
       var position = animate ? getInitialBarPos(i) : getBarPos(d, i),
           length = animate ? 0 : getBarLength(d, i),
-          radius = series.measures.elementAt(_reverseIdx(i)) == roundIdx ? RADIUS : 0,
+          radius =
+          series.measures.elementAt(_reverseIdx(i)) == roundIdx ? RADIUS : 0,
           path = (length != 0)
               ? verticalBars
                   ? topRoundedRect(0, position, barWidth, length, radius)
                   : rightRoundedRect(position, 0, length, barWidth, radius)
               : '';
-      e.attributes['data-offset'] = verticalBars ?
-          position.toString() : (position + length).toString();
+      e.attributes['data-offset'] =
+          verticalBars ? position.toString() : (position + length).toString();
       return path;
     };
 
@@ -189,8 +191,8 @@
       rect.classes.add('stack-rdr-bar');
 
       rect.attributes
-        ..['d'] = buildPath (d == null ? 0 : d, i, rect, animateBarGroups,
-            roundIndex)
+        ..['d'] =
+            buildPath(d == null ? 0 : d, i, rect, animateBarGroups, roundIndex)
         ..['stroke-width'] = '${theme.defaultStrokeWidth}px'
         ..['fill'] = color
         ..['stroke'] = color;
@@ -235,7 +237,7 @@
           var row = int.parse(e.parent.dataset['row']),
               roundIndex = _lastMeasureWithData[row];
           return buildPath(d == null ? 0 : d, i, e, false, roundIndex);
-      });
+        });
     }
 
     bar.exit.remove();
@@ -285,12 +287,12 @@
     var groups = host.querySelectorAll('.stack-rdr-rowgroup');
     if (groups == null || groups.isEmpty) return;
 
-    for(int i = 0, len = groups.length; i < len; ++i) {
+    for (int i = 0, len = groups.length; i < len; ++i) {
       var group = groups.elementAt(i),
           bars = group.querySelectorAll('.stack-rdr-bar'),
           row = int.parse(group.dataset['row']);
 
-      for(int j = 0, barsCount = bars.length; j < barsCount; ++j) {
+      for (int j = 0, barsCount = bars.length; j < barsCount; ++j) {
         var bar = bars.elementAt(j),
             column = int.parse(bar.dataset['column']),
             color = colorForValue(column, row),
@@ -314,8 +316,7 @@
     if (controller == null) return;
     var rowStr = e.parent.dataset['row'];
     var row = rowStr != null ? int.parse(rowStr) : null;
-    controller.add(new DefaultChartEventImpl(
-        scope.event, area, series, row,
+    controller.add(new DefaultChartEventImpl(scope.event, area, series, row,
         series.measures.elementAt(_reverseIdx(index)), data));
   }
 
diff --git a/packages/charted/lib/charts/chart_area.dart b/packages/charted/lib/charts/chart_area.dart
index f6c9d2f..e115f64 100644
--- a/packages/charted/lib/charts/chart_area.dart
+++ b/packages/charted/lib/charts/chart_area.dart
@@ -57,16 +57,13 @@
   ///   change.  When not set, [draw] must be called to update the chart.
   /// - When [useTwoDimensionAxes] is set, the chart uses both 'x' and 'y'
   ///   axes as dimensions.
-  factory CartesianArea(
-      dynamic host,
-      ChartData data,
-      ChartConfig config, {
-      bool autoUpdate: false,
-      bool useTwoDimensionAxes: false,
-      bool useRowColoring: false,
-      ChartState state }) =>
-          new DefaultCartesianAreaImpl(host, data, config, autoUpdate,
-              useTwoDimensionAxes, useRowColoring, state);
+  factory CartesianArea(dynamic host, ChartData data, ChartConfig config,
+          {bool autoUpdate: false,
+          bool useTwoDimensionAxes: false,
+          bool useRowColoring: false,
+          ChartState state}) =>
+      new DefaultCartesianAreaImpl(host, data, config, autoUpdate,
+          useTwoDimensionAxes, useRowColoring, state);
 }
 
 ///
@@ -84,13 +81,9 @@
   /// Layout area always uses row coloring.
   bool get useRowColoring => true;
 
-  factory LayoutArea(
-      dynamic host,
-      ChartData data,
-      ChartConfig config, {
-      bool autoUpdate: false,
-      ChartState state }) =>
-          new DefaultLayoutAreaImpl(host, data, config, autoUpdate, state);
+  factory LayoutArea(dynamic host, ChartData data, ChartConfig config,
+          {bool autoUpdate: false, ChartState state}) =>
+      new DefaultLayoutAreaImpl(host, data, config, autoUpdate, state);
 }
 
 ///
diff --git a/packages/charted/lib/charts/chart_config.dart b/packages/charted/lib/charts/chart_config.dart
index 9a65883..73ce850 100644
--- a/packages/charted/lib/charts/chart_config.dart
+++ b/packages/charted/lib/charts/chart_config.dart
@@ -66,8 +66,8 @@
   bool switchAxesForRTL;
 
   /// Factory method to create an instance of the default implementation
-  factory ChartConfig(
-      Iterable<ChartSeries> series, Iterable<int> dimensions) = DefaultChartConfigImpl;
+  factory ChartConfig(Iterable<ChartSeries> series,
+      Iterable<int> dimensions) = DefaultChartConfigImpl;
 }
 
 ///
diff --git a/packages/charted/lib/charts/chart_data.dart b/packages/charted/lib/charts/chart_data.dart
index f6304c0..de58dbc 100644
--- a/packages/charted/lib/charts/chart_data.dart
+++ b/packages/charted/lib/charts/chart_data.dart
@@ -20,8 +20,8 @@
   Iterable<Iterable> get rows;
 
   /// Create a new instance of [ChartData]'s internal implementation
-  factory ChartData(
-      Iterable<ChartColumnSpec> columns, Iterable<Iterable> rows) = DefaultChartDataImpl;
+  factory ChartData(Iterable<ChartColumnSpec> columns,
+      Iterable<Iterable> rows) = DefaultChartDataImpl;
 }
 
 ///
@@ -37,7 +37,6 @@
   ChartData transform(ChartData source);
 }
 
-
 ///
 /// Implementation of [ChangeRecord], that is used to notify when rows get added
 /// or removed to ChartData
@@ -74,9 +73,9 @@
   static const String TYPE_STRING = 'string';
   static const String TYPE_TIMESTAMP = 'timestamp';
 
-  static const List ORDINAL_SCALES = const [ TYPE_STRING ];
-  static const List LINEAR_SCALES = const [ TYPE_NUMBER ];
-  static const List TIME_SCALES = const [ TYPE_DATE, TYPE_TIMESTAMP ];
+  static const List ORDINAL_SCALES = const [TYPE_STRING];
+  static const List LINEAR_SCALES = const [TYPE_NUMBER];
+  static const List TIME_SCALES = const [TYPE_DATE, TYPE_TIMESTAMP];
 
   /// Formatter for values that belong to this column
   final FormatFunction formatter;
@@ -102,20 +101,20 @@
   Scale createDefaultScale() {
     if (useOrdinalScale == true) {
       return new OrdinalScale();
-    }
-    else if (LINEAR_SCALES.contains(type)) {
+    } else if (LINEAR_SCALES.contains(type)) {
       return new LinearScale();
-    }
-    else if (TIME_SCALES.contains(type)) {
+    } else if (TIME_SCALES.contains(type)) {
       return new TimeScale();
     }
     return null;
   }
 
-  ChartColumnSpec({this.label, String type : TYPE_NUMBER,
-      this.formatter, bool useOrdinalScale})
-      : useOrdinalScale =
-            useOrdinalScale == true ||
+  ChartColumnSpec(
+      {this.label,
+      String type: TYPE_NUMBER,
+      this.formatter,
+      bool useOrdinalScale})
+      : useOrdinalScale = useOrdinalScale == true ||
             useOrdinalScale == null && ORDINAL_SCALES.contains(type),
         type = type;
 }
diff --git a/packages/charted/lib/charts/chart_legend.dart b/packages/charted/lib/charts/chart_legend.dart
index a55a918..8cc69d0 100644
--- a/packages/charted/lib/charts/chart_legend.dart
+++ b/packages/charted/lib/charts/chart_legend.dart
@@ -24,8 +24,8 @@
 
   /// Factory to create an instance of the default implementation.
   factory ChartLegend(Element host,
-      {maxItems: 0, title: '', showValues: false}) =>
-          new DefaultChartLegendImpl(host, maxItems, showValues, title);
+          {maxItems: 0, title: '', showValues: false}) =>
+      new DefaultChartLegendImpl(host, maxItems, showValues, title);
 }
 
 ///
@@ -52,6 +52,11 @@
   /// List of series that this column is part of
   Iterable<ChartSeries> series;
 
-  ChartLegendItem({this.index, this.color,
-      this.label, this.description, this.series, this.value});
+  ChartLegendItem(
+      {this.index,
+      this.color,
+      this.label,
+      this.description,
+      this.series,
+      this.value});
 }
diff --git a/packages/charted/lib/charts/chart_series.dart b/packages/charted/lib/charts/chart_series.dart
index 8582fe4..4d0fbd9 100644
--- a/packages/charted/lib/charts/chart_series.dart
+++ b/packages/charted/lib/charts/chart_series.dart
@@ -54,12 +54,12 @@
 
   /// Factory function to create an instance of internal implementation of
   /// [ChartSeries].
-  factory ChartSeries(String name, Iterable<int> measures,
-      ChartRenderer renderer, { Iterable<String> measureAxisIds : null }) =>
-          new DefaultChartSeriesImpl(name, measures, renderer, measureAxisIds);
+  factory ChartSeries(
+          String name, Iterable<int> measures, ChartRenderer renderer,
+          {Iterable<String> measureAxisIds: null}) =>
+      new DefaultChartSeriesImpl(name, measures, renderer, measureAxisIds);
 }
 
-
 ///
 /// Implementation of [ChangeRecord] that is used to notify changes to
 /// [ChartSeries].  Currently, only changes to measures and measureAxisIds
@@ -70,4 +70,4 @@
   final ChartSeries series;
 
   const ChartSeriesChangeRecord(this.series);
-}
\ No newline at end of file
+}
diff --git a/packages/charted/lib/charts/chart_state.dart b/packages/charted/lib/charts/chart_state.dart
index d807677..7909ada 100644
--- a/packages/charted/lib/charts/chart_state.dart
+++ b/packages/charted/lib/charts/chart_state.dart
@@ -13,38 +13,50 @@
 /// Selection and visibility
 ///
 abstract class ChartState implements ChangeNotifier {
-  static int COL_SELECTED       = 0x001;
-  static int COL_UNSELECTED     = 0x002;
-  static int COL_PREVIEW        = 0x004;
-  static int COL_HIDDEN         = 0x008;
-  static int COL_HIGHLIGHTED    = 0x010;
-  static int COL_UNHIGHLIGHTED  = 0x020;
-  static int COL_HOVERED        = 0x040;
-  static int VAL_HIGHLIGHTED    = 0x080;
-  static int VAL_UNHIGHLIGHTED  = 0x100;
-  static int VAL_HOVERED        = 0x200;
+  static int COL_SELECTED = 0x001;
+  static int COL_UNSELECTED = 0x002;
+  static int COL_PREVIEW = 0x004;
+  static int COL_HIDDEN = 0x008;
+  static int COL_HIGHLIGHTED = 0x010;
+  static int COL_UNHIGHLIGHTED = 0x020;
+  static int COL_HOVERED = 0x040;
+  static int VAL_HIGHLIGHTED = 0x080;
+  static int VAL_UNHIGHLIGHTED = 0x100;
+  static int VAL_HOVERED = 0x200;
 
-  static const COL_SELECTED_CLASS       = 'col-selected';
-  static const COL_UNSELECTED_CLASS     = 'col-unselected';
-  static const COL_PREVIEW_CLASS        = 'col-previewed';
-  static const COL_HIDDEN_CLASS         = 'col-hidden';
-  static const COL_HIGHLIGHTED_CLASS    = 'col-highlighted';
-  static const COL_UNHIGHLIGHTED_CLASS  = 'col-unhighlighted';
-  static const COL_HOVERED_CLASS        = 'col-hovered';
-  static const VAL_HIGHLIGHTED_CLASS    = 'row-highlighted';
-  static const VAL_UNHIGHLIGHTED_CLASS  = 'row-unhighlighted';
-  static const VAL_HOVERED_CLASS        = 'row-hovered';
+  static const COL_SELECTED_CLASS = 'col-selected';
+  static const COL_UNSELECTED_CLASS = 'col-unselected';
+  static const COL_PREVIEW_CLASS = 'col-previewed';
+  static const COL_HIDDEN_CLASS = 'col-hidden';
+  static const COL_HIGHLIGHTED_CLASS = 'col-highlighted';
+  static const COL_UNHIGHLIGHTED_CLASS = 'col-unhighlighted';
+  static const COL_HOVERED_CLASS = 'col-hovered';
+  static const VAL_HIGHLIGHTED_CLASS = 'row-highlighted';
+  static const VAL_UNHIGHLIGHTED_CLASS = 'row-unhighlighted';
+  static const VAL_HOVERED_CLASS = 'row-hovered';
 
-  static const COLUMN_CLASS_NAMES = const[
-    COL_SELECTED_CLASS, COL_UNSELECTED_CLASS, COL_PREVIEW_CLASS,
-    COL_HIGHLIGHTED_CLASS, COL_UNHIGHLIGHTED_CLASS, COL_HIDDEN_CLASS,
-    COL_HOVERED_CLASS];
+  static const COLUMN_CLASS_NAMES = const [
+    COL_SELECTED_CLASS,
+    COL_UNSELECTED_CLASS,
+    COL_PREVIEW_CLASS,
+    COL_HIGHLIGHTED_CLASS,
+    COL_UNHIGHLIGHTED_CLASS,
+    COL_HIDDEN_CLASS,
+    COL_HOVERED_CLASS
+  ];
 
-  static const VALUE_CLASS_NAMES = const[
-    COL_SELECTED_CLASS, COL_UNSELECTED_CLASS, COL_PREVIEW_CLASS,
-    COL_HIGHLIGHTED_CLASS, COL_UNHIGHLIGHTED_CLASS, COL_HIDDEN_CLASS,
-    COL_HOVERED_CLASS, VAL_HIGHLIGHTED_CLASS, VAL_UNHIGHLIGHTED_CLASS,
-    VAL_HOVERED_CLASS];
+  static const VALUE_CLASS_NAMES = const [
+    COL_SELECTED_CLASS,
+    COL_UNSELECTED_CLASS,
+    COL_PREVIEW_CLASS,
+    COL_HIGHLIGHTED_CLASS,
+    COL_UNHIGHLIGHTED_CLASS,
+    COL_HIDDEN_CLASS,
+    COL_HOVERED_CLASS,
+    VAL_HIGHLIGHTED_CLASS,
+    VAL_UNHIGHLIGHTED_CLASS,
+    VAL_HOVERED_CLASS
+  ];
 
   /// List of selected items.
   /// - Contains a column on CartesianArea if useRowColoring is false.
@@ -64,11 +76,11 @@
 
   /// Currently highlighted value, if any, represented as column and row.
   /// Highlight is result of a click on certain value.
-  Iterable<Pair<int,int>> highlights;
+  Iterable<Pair<int, int>> highlights;
 
   /// Currently hovered value, if any, represented as column and row.
   /// Hover is result of mouse moving over a certian value in chart.
-  Pair<int,int> hovered;
+  Pair<int, int> hovered;
 
   /// Ensure that a row or column is visible.
   bool unhide(int id);
@@ -126,8 +138,8 @@
 /// values in [ChartData].
 ///
 class ChartHighlightChangeRecord implements ChangeRecord {
-  final Pair<int,int> remove;
-  final Pair<int,int> add;
+  final Pair<int, int> remove;
+  final Pair<int, int> add;
   const ChartHighlightChangeRecord({this.add, this.remove});
 }
 
@@ -136,7 +148,7 @@
 /// values in [ChartData].
 ///
 class ChartHoverChangeRecord implements ChangeRecord {
-  final Pair<int,int> hovered;
+  final Pair<int, int> hovered;
   const ChartHoverChangeRecord(this.hovered);
 }
 
diff --git a/packages/charted/lib/charts/chart_theme.dart b/packages/charted/lib/charts/chart_theme.dart
index bea1f72..1515f87 100644
--- a/packages/charted/lib/charts/chart_theme.dart
+++ b/packages/charted/lib/charts/chart_theme.dart
@@ -50,7 +50,7 @@
   String get defaultFont;
 
   /// Easing function for the transition
-  EasingFunction  get transitionEasingType => Transition.defaultEasingType;
+  EasingFunction get transitionEasingType => Transition.defaultEasingType;
 
   /// Easing mode for the transition
   EasingModeFunction get transitionEasingMode => Transition.defaultEasingMode;
diff --git a/packages/charted/lib/charts/data_transformers/aggregation.dart b/packages/charted/lib/charts/data_transformers/aggregation.dart
index ffde9ee..1efe921 100644
--- a/packages/charted/lib/charts/data_transformers/aggregation.dart
+++ b/packages/charted/lib/charts/data_transformers/aggregation.dart
@@ -1,35 +1,31 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
-/**
- * Function callback to filter items in the input
- */
+///Function callback to filter items in the input
 typedef bool AggregationFilterFunc(var item);
 
 typedef dynamic FieldAccessor(dynamic item, dynamic key);
 
-
-// TODO(midoringo, prsd): Consider splitting each aggregation type into its own
-// strategy object for readability, maintainability, and scalability.
-/**
- * Given list of items, dimensions and facts, compute
- * aggregates (COUNT, SUM, MIN, MAX) for facts at each dimension level.
- */
+/// Given list of items, dimensions and facts, compute
+/// aggregates (COUNT, SUM, MIN, MAX) for facts at each dimension level.
 class AggregationModel {
-
   // Number of aggregations we collect on each fact
   int _aggregationTypesCount = 0;
 
   // Currently supported list of aggregations.
-  static final List<String> supportedAggregationTypes =
-      ['sum', 'min', 'max', 'valid'];
+  static final List<String> supportedAggregationTypes = [
+    'sum',
+    'min',
+    'max',
+    'valid'
+  ];
 
   // Computed aggregation types.
   List<String> computedAggregationTypes;
@@ -103,18 +99,15 @@
   FieldAccessor dimensionAccessor;
   FieldAccessor factsAccessor;
 
-  /**
-   * Create a new [AggregationModel] from a [collection] of items,
-   * list of [dimensions] on which the items are grouped and a list of [facts]
-   * on which aggregations are computed.
-   */
-  AggregationModel(List collection, List dimensions,
-                   List facts,
-                   { List<String> aggregationTypes,
-                     this.walkThroughMap: false,
-                     this.comparators,
-                     this.dimensionAccessor,
-                     this.factsAccessor}) {
+  /// Create a new [AggregationModel] from a [collection] of items,
+  /// list of [dimensions] on which the items are grouped and a list of [facts]
+  /// on which aggregations are computed.
+  AggregationModel(List collection, List dimensions, List facts,
+      {List<String> aggregationTypes,
+      this.walkThroughMap: false,
+      this.comparators,
+      this.dimensionAccessor,
+      this.factsAccessor}) {
     _init(collection, dimensions, facts, aggregationTypes);
   }
 
@@ -127,17 +120,15 @@
   void _timeItEnd() {
     _timeItWatch.stop();
     _logger.info('[aggregations/$_timeItName] '
-                 '${_timeItWatch.elapsed.inMilliseconds}ms/${_rows.length}r');
+        '${_timeItWatch.elapsed.inMilliseconds}ms/${_rows.length}r');
   }
 
   List get factFields => _factFields;
   List get dimensionFields => _dimFields;
 
-  /**
-   * Initialize the view
-   */
-  void _init(List collection, List dimensions,
-             List facts, List<String> aggregationTypes) {
+  /// Initialize the view
+  void _init(List collection, List dimensions, List facts,
+      List<String> aggregationTypes) {
     if (collection == null) {
       throw new ArgumentError('Data cannot be empty or null');
     }
@@ -183,7 +174,7 @@
 
     _aggregationTypesCount = aggregationTypes.length;
     for (int i = 0; i < _aggregationTypesCount; i++) {
-      switch(aggregationTypes[i]) {
+      switch (aggregationTypes[i]) {
         case 'sum':
           _offsetSum = i;
           break;
@@ -204,9 +195,7 @@
     _preprocess();
   }
 
-  /**
-   * Re-calculate aggregations based on new dimensions.
-   */
+  /// Re-calculate aggregations based on new dimensions.
   void groupBy(List dimensions, [AggregationFilterFunc filter = null]) {
     if (dimensions == null) {
       dimensions = [];
@@ -217,13 +206,13 @@
 
     _dimPrefixLength = 0;
     while (_dimPrefixLength < _dimFields.length &&
-           _dimPrefixLength < savedDimFields.length &&
-           savedDimFields[_dimPrefixLength] == _dimFields[_dimPrefixLength]) {
+        _dimPrefixLength < savedDimFields.length &&
+        savedDimFields[_dimPrefixLength] == _dimFields[_dimPrefixLength]) {
       ++_dimPrefixLength;
     }
 
     _createBuffers();
-    _preprocess(groupBy:true);
+    _preprocess(groupBy: true);
 
     // For groupBy, compute immediately.
     compute(filter);
@@ -232,12 +221,11 @@
     _updateCachedEntities();
   }
 
-  /**
-   * Create buffers.
-   * This method is called when the object is being created and when
-   * a groupBy is called to change the dimensions on which
-   * aggregations are computed.
-   */
+  /// Create buffers.
+  ///
+  /// This method is called when the object is being created and when
+  /// a groupBy is called to change the dimensions on which
+  /// aggregations are computed.
   void _createBuffers() {
     // Create both when object is created and groupBy is called
     _dimEnumCache = new Int32List(_dimFields.length * _rows.length);
@@ -259,13 +247,11 @@
         (i) => i < _dimPrefixLength ? oldDimToInt[i] : new Map<dynamic, int>());
   }
 
-  /**
-   * Check cache entries
-   * When data is grouped by a new dimensions, entities that were
-   * created prior to the groupBy should be cleared and removed from cache
-   * if they aren't valid anymore.
-   * Update the entities that are valid after the groupBy.
-   */
+  /// Check cache entries
+  /// When data is grouped by a new dimensions, entities that were
+  /// created prior to the groupBy should be cleared and removed from cache
+  /// if they aren't valid anymore.
+  /// Update the entities that are valid after the groupBy.
   void _updateCachedEntities() {
     List keys = new List.from(_entityCache.keys, growable: false);
     keys.forEach((key) {
@@ -284,9 +270,7 @@
   }
 
   final Map<String, List> _parsedKeys = {};
-  /**
-   * Get value from a map-like object
-   */
+  /// Get value from a map-like object
   dynamic _fetch(var item, String key) {
     if (walkThroughMap && key.contains('.')) {
       return walk(item, key, _parsedKeys);
@@ -295,14 +279,11 @@
     }
   }
 
-  /*
-   * Preprocess Data
-   *  - Enumerate dimension values
-   *  - Create sort orders for dimension values
-   *  - Cache facts in lists
-   */
+  /// Preprocess Data
+  ///  - Enumerate dimension values
+  ///  - Create sort orders for dimension values
+  ///  - Cache facts in lists
   void _preprocess({bool groupBy: false}) {
-
     _timeItStart('preprocess');
 
     // Enumerate dimensions...
@@ -316,8 +297,8 @@
     int rowCount = _rows.length;
 
     for (int ri = 0, factsDataOffset = 0, dimDataOffset = 0;
-         ri < rowCount; ++ri, factsDataOffset += factsCount,
-         dimDataOffset += dimensionsCount) {
+        ri < rowCount;
+        ++ri, factsDataOffset += factsCount, dimDataOffset += dimensionsCount) {
       var item = _rows[ri];
 
       // Cache the fact values in the big buffer, but only
@@ -325,7 +306,7 @@
       // after initialization)
       if (!groupBy) {
         for (int fi = 0; fi < factsCount; fi++) {
-          var value = factsAccessor(item,_factFields[fi]);
+          var value = factsAccessor(item, _factFields[fi]);
           _factsCache[factsDataOffset + fi] =
               (value == null) ? double.NAN : value.toDouble();
         }
@@ -358,8 +339,9 @@
       // When a comparator is not specified, our implementation of the
       // comparator tries to gracefully handle null values.
       dimensionVals.sort(
-          comparators != null && comparators.containsKey(_dimFields[i]) ?
-              comparators[_dimFields[i]] : _defaultDimComparator);
+          comparators != null && comparators.containsKey(_dimFields[i])
+              ? comparators[_dimFields[i]]
+              : _defaultDimComparator);
 
       for (int si = 0; si < retval.length; ++si) {
         retval[_dimToIntMap[i][dimensionVals[si]]] = si;
@@ -383,14 +365,12 @@
 
   // Ensures that null dimension values don't cause an issue with sorting
   _defaultDimComparator(Comparable left, Comparable right) =>
-      (left == null && right == null) ? 0 :
-          (left == null) ? -1 :
-              (right == null) ? 1 : left.compareTo(right);
+      (left == null && right == null)
+          ? 0
+          : (left == null) ? -1 : (right == null) ? 1 : left.compareTo(right);
 
-  /*
-   * Given item indices in rows, compare them based
-   * on the sort orders created while preprocessing data.
-   */
+  /// Given item indices in rows, compare them based
+  /// on the sort orders created while pre-processing data.
   _comparator(int one, int two) {
     if (one == two) {
       return 0;
@@ -401,7 +381,7 @@
 
     for (int i = 0; i < _dimFields.length; ++i) {
       int diff = _dimSortOrders[i][_dimEnumCache[offsetOne + i]] -
-                 _dimSortOrders[i][_dimEnumCache[offsetTwo + i]];
+          _dimSortOrders[i][_dimEnumCache[offsetTwo + i]];
       if (diff != 0) {
         return diff;
       }
@@ -409,18 +389,17 @@
     return 0;
   }
 
-  /**
-   * Compute aggregations
-   * If [filter] is not null, it would be used to filter out items that
-   * should not be included in the aggregates.
-   */
+  /// Compute aggregations
+  /// If [filter] is not null, it would be used to filter out items that
+  /// should not be included in the aggregates.
   void compute([AggregationFilterFunc filter = null]) {
     _timeItStart('compute');
 
     _dimToAggrMap = new Map<String, int>();
     _aggregations = new Float64List(AGGREGATIONS_BUFFER_LENGTH);
-    _filterResults = filter == null ?
-        null : new List<int>.filled((_rows.length ~/ SMI_BITS) + 1, 0);
+    _filterResults = filter == null
+        ? null
+        : new List<int>.filled((_rows.length ~/ SMI_BITS) + 1, 0);
 
     int rowCount = _rows.length;
     int dimensionCount = _dimFields.length;
@@ -439,10 +418,9 @@
     _dimToAggrMap[''] = 0;
     _aggregations[_offsetSortedIndex] = 0.0;
 
-
     for (int ri = 0, index = 0, dimensionDataOffset = 0, factsDataOffset = 0;
-         ri < rowCount; ++ri, reset = false) {
-
+        ri < rowCount;
+        ++ri, reset = false) {
       // If filter is not null, check if this row must be included in
       // the aggregations and mark it accordingly.
       index = _sorted[ri];
@@ -472,8 +450,8 @@
           currentDim[ci + 1] = currentBufferPos;
 
           // Save location to aggregations position in the buffer
-          _dimToAggrMap[new List.generate(di + 1,
-              (i) => currentDim[2 * i]).join(':')] = currentBufferPos;
+          _dimToAggrMap[new List.generate(di + 1, (i) => currentDim[2 * i])
+              .join(':')] = currentBufferPos;
 
           // Store items start position
           _aggregations[currentBufferPos + _offsetSortedIndex] = ri.toDouble();
@@ -485,8 +463,8 @@
           isNewDimension = true;
         }
 
-        _updateAggregationsAt(currentDim[ci + 1],
-            factsDataOffset, isNewDimension);
+        _updateAggregationsAt(
+            currentDim[ci + 1], factsDataOffset, isNewDimension);
         isNewDimension = false;
       }
     }
@@ -494,20 +472,17 @@
     _timeItEnd();
   }
 
-  /**
-   * Helper function that does the actual aggregations.
-   * This function is called once per row per dimension.
-   */
-  _updateAggregationsAt(int aggrDataOffset,
-                        int factsDataOffset, bool isNewDimension) {
+  /// Helper function that does the actual aggregations.
+  /// This function is called once per row per dimension.
+  _updateAggregationsAt(
+      int aggrDataOffset, int factsDataOffset, bool isNewDimension) {
     // Update count.
     _aggregations[aggrDataOffset + _offsetFilteredCount] += 1;
 
     // Update aggregation for each of the facts.
     for (int fi = 0, bufferFactOffset = aggrDataOffset;
-         fi < _factFields.length;
-         bufferFactOffset += _aggregationTypesCount, ++fi) {
-
+        fi < _factFields.length;
+        bufferFactOffset += _aggregationTypesCount, ++fi) {
       double factValue = _factsCache[factsDataOffset + fi];
       if (factValue.isNaN) {
         continue;
@@ -519,14 +494,16 @@
       }
 
       // Min
-      if (_offsetMin != null && (isNewDimension || factValue <
-          _aggregations[bufferFactOffset + _offsetMin])) {
+      if (_offsetMin != null &&
+          (isNewDimension ||
+              factValue < _aggregations[bufferFactOffset + _offsetMin])) {
         _aggregations[bufferFactOffset + _offsetMin] = factValue;
       }
 
       // Max
-      if (_offsetMax != null && (isNewDimension || factValue >
-          _aggregations[bufferFactOffset + _offsetMax])) {
+      if (_offsetMax != null &&
+          (isNewDimension ||
+              factValue > _aggregations[bufferFactOffset + _offsetMax])) {
         _aggregations[bufferFactOffset + _offsetMax] = factValue;
       }
 
@@ -537,51 +514,41 @@
     }
   }
 
-  /*
-   * TODO(prsd):
-   * 1. Implementation of updates and posting updates to entities.
-   *    patchEntity and addToEntity must add listeners on AggregationItems
-   *    and any changes must be propagated to entities.
-   * 2. Updates (add/remove/update) should do their best to update the
-   *    aggregations and then maybe do a delayed recomputation (sort etc;)
-   */
+  // TODO(prsd):
+  // 1. Implementation of updates and posting updates to entities.
+  //    patchEntity and addToEntity must add listeners on AggregationItems
+  //    and any changes must be propagated to entities.
+  // 2. Updates (add/remove/update) should do their best to update the
+  //    aggregations and then maybe do a delayed recomputation (sort etc;)
 
-  /**
-   * Update an item.
-   * If aggregates were already computed, they are updated to reflect the
-   * new value and any observers are notified.
-   */
+  /// Update an item.
+  /// If aggregates were already computed, they are updated to reflect the
+  /// new value and any observers are notified.
   void updateItem(dynamic item, String field) {
     throw new UnimplementedError();
   }
 
-  /**
-   * Add a new item.
-   * If aggregates were already computed, they are updated to reflect
-   * values on the new item.
-   */
+  /// Add a new item.
+  /// If aggregates were already computed, they are updated to reflect
+  /// values on the new item.
   void addItem(dynamic item) {
     throw new UnimplementedError();
   }
 
-  /**
-   * Remove an existing item.
-   * If aggregates were already computed, they are updated to reflect
-   * facts on the removed item.
-   */
+  /// Remove an existing item.
+  /// If aggregates were already computed, they are updated to reflect
+  /// facts on the removed item.
   void removeItem(dynamic item) {
     throw new UnimplementedError();
   }
 
-  /**
-   * Return an [AggregationItem] that represents facts for dimension
-   * represented by [dimension] Only one instance of an entity is created
-   * per dimension (even if this function is called multiple times)
-   *
-   * Callers of this method can observe the returned entity for updates to
-   * aggregations caused by changes to filter or done through add, remove
-   * or modify of items in the collection.
-   */
+  /// Return an [AggregationItem] that represents facts for dimension
+  /// represented by [dimension] Only one instance of an entity is created
+  /// per dimension (even if this function is called multiple times)
+  ///
+  /// Callers of this method can observe the returned entity for updates to
+  /// aggregations caused by changes to filter or done through add, remove
+  /// or modify of items in the collection.
   AggregationItem facts(List dimension) {
     List<int> enumeratedList = new List<int>();
     for (int i = 0; i < dimension.length; ++i) {
@@ -599,9 +566,7 @@
     return item;
   }
 
-  /**
-   * Return a list of values that are present for a dimension field.
-   */
+  /// Return a list of values that are present for a dimension field.
   List valuesForDimension(dynamic dimensionFieldName) {
     int di = _dimFields.indexOf(dimensionFieldName);
     if (di < 0) {
@@ -609,22 +574,21 @@
     }
     List values = new List.from(_dimToIntMap[di].keys);
     values.sort(
-        comparators != null && comparators.containsKey(dimensionFieldName) ?
-            comparators[dimensionFieldName] : _defaultDimComparator);
+        comparators != null && comparators.containsKey(dimensionFieldName)
+            ? comparators[dimensionFieldName]
+            : _defaultDimComparator);
     return values;
   }
 }
 
-/**
- * Parse a path for nested map-like objects.
- * Caches the parsed key in the passed map.
- *
- * Takes map keys of the format:
- *     "list(key=val;val=m).another(state=good).state"
- * and outputs:
- *     ["list", {"key": "val", "val": "m"},
- *      "another", {"state": "good"}, "state"]
- */
+/// Parse a path for nested map-like objects.
+/// Caches the parsed key in the passed map.
+///
+/// Takes map keys of the format:
+///     "list(key=val;val=m).another(state=good).state"
+/// and outputs:
+///     ["list", {"key": "val", "val": "m"},
+///      "another", {"state": "good"}, "state"]
 List _parseKey(String key, Map parsedKeysCache) {
   List parts = parsedKeysCache == null ? null : parsedKeysCache[key];
   if (parts == null && key != null) {
@@ -678,30 +642,28 @@
   return parts;
 }
 
-/**
- * Walk a map-like structure that could have list in the path.
- *
- * Example:
- *     Map testMap = {
- *       "first": "firstval",
- *       "list": [
- *         { "val": "m",
- *           "key": "val",
- *           "another": [
- *             { 'state': 'good' },
- *             { 'state': 'bad' }
- *           ]
- *         },
- *         { "val": "m", "key": "invalid" },
- *         { "val": "o" }
- *       ]
- *     };
- *
- *  For the above map:
- *     walk(testMap, "list(key=val;val=m).another(state=good).state");
- *  outputs:
- *     good
- */
+/// Walk a map-like structure that could have list in the path.
+///
+/// Example:
+///     Map testMap = {
+///       "first": "firstval",
+///       "list": [
+///         { "val": "m",
+///           "key": "val",
+///           "another": [
+///             { 'state': 'good' },
+///             { 'state': 'bad' }
+///           ]
+///         },
+///         { "val": "m", "key": "invalid" },
+///         { "val": "o" }
+///       ]
+///     };
+///
+///  For the above map:
+///     walk(testMap, "list(key=val;val=m).another(state=good).state");
+///  outputs:
+///     good
 dynamic walk(initial, String key, Map parsedKeyCache) {
   List parts = _parseKey(key, parsedKeyCache);
   return parts.fold(initial, (current, part) {
@@ -712,7 +674,7 @@
         bool match = true;
         part.forEach((key, val) {
           if ((key.contains('.') &&
-               walk(part, key, parsedKeyCache).toString() != val) ||
+                  walk(part, key, parsedKeyCache).toString() != val) ||
               part[key] != val) {
             match = false;
           }
diff --git a/packages/charted/lib/charts/data_transformers/aggregation_item.dart b/packages/charted/lib/charts/data_transformers/aggregation_item.dart
index 17c6413..1c9f564 100644
--- a/packages/charted/lib/charts/data_transformers/aggregation_item.dart
+++ b/packages/charted/lib/charts/data_transformers/aggregation_item.dart
@@ -1,59 +1,44 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
-/**
- * AggregationItem is created by [AggregationModel] to make access to facts
- * observable. Users must use AggregationItem.isValid before trying to access
- * the aggregations.
- */
+/// AggregationItem is created by [AggregationModel] to make access to facts
+/// observable. Users must use AggregationItem.isValid before trying to access
+/// the aggregations.
 abstract class AggregationItem extends ChangeNotifier {
-  /**
-   * List of dimension fields in effect
-   */
+  /// List of dimension fields in effect
   List<String> dimensions;
 
-  /**
-   * Check if this entity is valid.
-   * Currently the only case where an entity becomes invalid
-   * is when a groupBy is called on the model.
-   */
+  /// Check if this entity is valid.
+  /// Currently the only case where an entity becomes invalid
+  /// is when a groupBy is called on the model.
   bool get isValid;
 
-  /**
-   * Fetch the fact from AggregationModel and return it
-   * Currently takes keys in the form of "sum(spend)", where sum is
-   * the aggregation type and spend is fact's field name.
-   *
-   * Currently, "sum", "count", "min", "max", "avg", "valid" and "avgOfValid"
-   * are supported as the operators.
-   */
+  /// Fetch the fact from AggregationModel and return it
+  /// Currently takes keys in the form of "sum(spend)", where sum is
+  /// the aggregation type and spend is fact's field name.
+  ///
+  /// Currently, "sum", "count", "min", "max", "avg", "valid" and "avgOfValid"
+  /// are supported as the operators.
+  operator [](String key);
 
-  operator[](String key);
-
-  /**
-   * Check if we support a given key.
-   */
+  /// Check if we support a given key.
   bool containsKey(String key);
 
-  /**
-   * List of valid field names for this entity.
-   * It's the combined list of accessors for individual items, items in
-   * the next dimension and all possible facts defined on the view.
-   */
+  /// List of valid field names for this entity.
+  /// It's the combined list of accessors for individual items, items in
+  /// the next dimension and all possible facts defined on the view.
   Iterable<String> get fieldNames;
 }
 
-/*
- * Implementation of AggregationItem
- * Instances of _AggregationItemImpl are created only by AggregationModel
- */
+/// Implementation of AggregationItem
+/// Instances of _AggregationItemImpl are created only by AggregationModel
 class _AggregationItemImpl extends ChangeNotifier implements AggregationItem {
   static final List<String> derivedAggregationTypes = ['count', 'avg'];
 
@@ -64,9 +49,7 @@
 
   int _factsOffset;
 
-  /*
-   * Currently entities are created only when they have valid aggregations
-   */
+  /// Currently entities are created only when they have valid aggregations
   _AggregationItemImpl(this.model, this.dimensions, this._key) {
     if (model == null) {
       throw new ArgumentError('Model cannot be null');
@@ -79,23 +62,19 @@
     _factsOffset = model._dimToAggrMap[_key];
   }
 
-  /**
-   * _dimToAggrMap got updated on the model, update ourselves accordingly
-   */
+  /// _dimToAggrMap got updated on the model, update ourselves accordingly
   void update() {
     _factsOffset = model._dimToAggrMap[_key];
   }
 
-  /*
-   * Mark this entity as invalid.
-   */
+  /// Mark this entity as invalid.
   void clear() {
     _factsOffset = null;
   }
 
   bool get isValid => _factsOffset != null;
 
-  dynamic operator[](String key) {
+  dynamic operator [](String key) {
     if (!isValid) {
       throw new StateError('Entity is not valid anymore');
     }
@@ -116,11 +95,10 @@
 
     // Try parsing int if every element in factFields is int.
     if (model._factFields.every((e) => e is int)) {
-      factIndex = model._factFields.indexOf(int.parse(factName,
-          onError: (e) {
-            throw new ArgumentError('Type of factFields are int but factName' +
-                'contains non int value');
-          }));
+      factIndex = model._factFields.indexOf(int.parse(factName, onError: (e) {
+        throw new ArgumentError('Type of factFields are int but factName' +
+            'contains non int value');
+      }));
     }
     if (factIndex == -1) {
       throw new ArgumentError('Model not configured for ${factName}');
@@ -128,7 +106,8 @@
 
     int offset = _factsOffset + factIndex * model._aggregationTypesCount;
     // No items for the corresponding fact, so return null.
-    if (aggrFunc != 'count' && aggrFunc != 'avg' &&
+    if (aggrFunc != 'count' &&
+        aggrFunc != 'avg' &&
         model._aggregations[offset + model._offsetCnt].toInt() == 0) {
       return null;
     }
@@ -136,13 +115,13 @@
     if (aggrFuncIndex != -1) {
       return model._aggregations[offset + aggrFuncIndex];
     } else if (aggrFunc == 'count') {
-      return model._aggregations[_factsOffset +
-                                 model._offsetFilteredCount].toInt();
+      return model._aggregations[_factsOffset + model._offsetFilteredCount]
+          .toInt();
     } else if (aggrFunc == 'avg') {
       return model._aggregations[offset + model._offsetSum] /
-             model._aggregations[_factsOffset + model._offsetFilteredCount].
-          toInt();
-    }  else if (aggrFunc == 'avgOfValid') {
+          model._aggregations[_factsOffset + model._offsetFilteredCount]
+              .toInt();
+    } else if (aggrFunc == 'avgOfValid') {
       return model._aggregations[offset + model._offsetSum] /
           model._aggregations[offset + model._offsetCnt].toInt();
     }
@@ -198,9 +177,7 @@
     return model._itemFieldNamesCache;
   }
 
-  /*
-   * TODO(prsd): Implementation of [Observable]
-   */
+  // TODO(prsd): Implementation of [Observable]
   Stream<List<ChangeRecord>> get changes {
     throw new UnimplementedError();
   }
@@ -218,12 +195,12 @@
   int _count;
   int _endOfRows;
 
-  _AggregationItemsIterator(this.model, List<String> this.dimensions,
-                           String this.key) {
+  _AggregationItemsIterator(
+      this.model, List<String> this.dimensions, String this.key) {
     int offset = model._dimToAggrMap[key];
     if (offset != null) {
-      int factsEndOffset = offset +
-          model._factFields.length * model._aggregationTypesCount;
+      int factsEndOffset =
+          offset + model._factFields.length * model._aggregationTypesCount;
       _start = model._aggregations[factsEndOffset].toInt();
       _count = model._aggregations[factsEndOffset + 1].toInt();
       _endOfRows = model._rows.length;
@@ -241,15 +218,14 @@
       return false;
     }
 
-    /*
-     * If model had a filter applied, then check if _current points to a
-     * filtered-in row, else skip till we find one.
-     * Also, make sure (even if something else went wrong) we don't go
-     * beyond the number of items in the model.
-     */
+    // If model had a filter applied, then check if _current points to a
+    // filtered-in row, else skip till we find one.
+    // Also, make sure (even if something else went wrong) we don't go
+    // beyond the number of items in the model.
     if (this.model._filterResults != null) {
       while ((this.model._filterResults[_current ~/ AggregationModel.SMI_BITS] &
-              (1 << _current % AggregationModel.SMI_BITS)) == 0 &&
+                  (1 << _current % AggregationModel.SMI_BITS)) ==
+              0 &&
           _current <= _endOfRows) {
         ++_current;
       }
diff --git a/packages/charted/lib/charts/data_transformers/aggregation_transformer.dart b/packages/charted/lib/charts/data_transformers/aggregation_transformer.dart
index 37db0b1..7cd8028 100644
--- a/packages/charted/lib/charts/data_transformers/aggregation_transformer.dart
+++ b/packages/charted/lib/charts/data_transformers/aggregation_transformer.dart
@@ -1,28 +1,25 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
-/**
- * Transforms the ChartData base on the specified dimension columns and facts
- * columns indices. The values in the facts columns will be aggregated by the
- * tree hierarchy generated by the dimension columns.  Expand and Collapse
- * methods may be called to display different levels of aggregation.
- *
- * The output ChartData produced by transform() will contain only columns in the
- * original ChartData that were specified in dimensions or facts column indices.
- * The output column will be re-ordered first by the indices specified in the
- * dimension column indices then by the facts column indices.  The data in the
- * cells of each row will also follow this rule.
- */
+/// Transforms the ChartData based on the specified dimension columns and facts
+/// columns indices. The values in the facts columns will be aggregated by the
+/// tree hierarchy generated by the dimension columns.  Expand and Collapse
+/// methods may be called to display different levels of aggregation.
+///
+/// The output ChartData produced by transform() will contain only columns in the
+/// original ChartData that were specified in dimensions or facts column indices.
+/// The output column will be re-ordered first by the indices specified in the
+/// dimension column indices then by the facts column indices.  The data in the
+/// cells of each row will also follow this rule.
 class AggregationTransformer extends ChangeNotifier
     implements ChartDataTransform, ChartData {
-
   static const String AGGREGATION_TYPE_SUM = 'sum';
   static const String AGGREGATION_TYPE_MIN = 'min';
   static const String AGGREGATION_TYPE_MAX = 'max';
@@ -40,16 +37,13 @@
   FieldAccessor _indexFieldAccessor = (List row, int index) => row[index];
   ChartData _data;
 
-  AggregationTransformer(this._dimensionColumnIndices,
-      this._factsColumnIndices,
+  AggregationTransformer(this._dimensionColumnIndices, this._factsColumnIndices,
       [String aggregationType = AGGREGATION_TYPE_SUM]) {
     _aggregationType = aggregationType;
   }
 
-  /**
-   * Transforms the ChartData base on the specified dimension columns and facts
-   * columns, aggregation type and currently expanded dimensions.
-   */
+  /// Transforms the ChartData base on the specified dimension columns and facts
+  /// columns, aggregation type and currently expanded dimensions.
   ChartData transform(ChartData data) {
     assert(data.columns.length > max(_dimensionColumnIndices));
     assert(data.columns.length > max(_factsColumnIndices));
@@ -59,11 +53,11 @@
     return this;
   }
 
-  /** Registers listeners if data.rows or data.columns are Observable. */
+  /// Registers listeners if data.rows or data.columns are Observable.
   _registerListeners() {
     _dataSubscriptions.dispose();
 
-    if(_data is Observable) {
+    if (_data is Observable) {
       var observable = (_data as Observable);
       _dataSubscriptions.add(observable.changes.listen((records) {
         _transform();
@@ -76,13 +70,12 @@
     }
   }
 
-  /**
-   * Performs the filter transform with _data.  This is called on transform and
-   * onChange if the input ChartData is Observable.
-   */
+  /// Performs the filter transform with _data.  This is called on transform and
+  /// onChange if the input ChartData is Observable.
   _transform() {
-    _model = new AggregationModel(_data.rows, _dimensionColumnIndices,
-        _factsColumnIndices, aggregationTypes: [_aggregationType],
+    _model = new AggregationModel(
+        _data.rows, _dimensionColumnIndices, _factsColumnIndices,
+        aggregationTypes: [_aggregationType],
         dimensionAccessor: _indexFieldAccessor,
         factsAccessor: _indexFieldAccessor);
     _model.compute();
@@ -105,17 +98,15 @@
     rows.addAll(transformedRows);
 
     // Process columns.
-    columns = new List<ChartColumnSpec>.generate(_selectedColumns.length, (index) =>
-        _data.columns.elementAt(_selectedColumns[index]));
+    columns = new List<ChartColumnSpec>.generate(_selectedColumns.length,
+        (index) => _data.columns.elementAt(_selectedColumns[index]));
   }
 
-  /**
-   * Fills the aggregatedRows List with data base on the set of expanded values
-   * recursively.  Currently when a dimension is expanded, rows are
-   * generated for its children but not for itself.  If we want to change the
-   * logic to include itself, just move the expand check around the else clause
-   * and always write a row of data whether it's expanded or not.
-   */
+  /// Fills the aggregatedRows List with data base on the set of expanded values
+  /// recursively.  Currently when a dimension is expanded, rows are
+  /// generated for its children but not for itself.  If we want to change the
+  /// logic to include itself, just move the expand check around the else clause
+  /// and always write a row of data whether it's expanded or not.
   _generateAggregatedRow(List<Iterable> aggregatedRows, List dimensionValues) {
     var entity = _model.facts(dimensionValues);
     var dimensionLevel = dimensionValues.length - 1;
@@ -125,7 +116,6 @@
     if (!_isExpanded(dimensionValues) ||
         dimensionValues.length == _dimensionColumnIndices.length) {
       aggregatedRows.add(new List.generate(_selectedColumns.length, (index) {
-
         // Dimension column.
         if (index < _dimensionColumnIndices.length) {
           if (index < dimensionLevel) {
@@ -152,10 +142,8 @@
     }
   }
 
-  /**
-   * Expands a specific dimension and optionally expands all of its parent
-   * dimensions.
-   */
+  /// Expands a specific dimension and optionally expands all of its parent
+  /// dimensions.
   void expand(List dimension, [bool expandParent = true]) {
     _expandAllDimension = false;
     _expandedSet.add(dimension);
@@ -168,10 +156,8 @@
     }
   }
 
-  /**
-   * Collapses a specific dimension and optionally collapse all of its
-   * Children dimensions.
-   */
+  /// Collapses a specific dimension and optionally collapse all of its
+  /// Children dimensions.
   void collapse(List dimension, [bool collapseChildren = true]) {
     _expandAllDimension = false;
     if (collapseChildren) {
@@ -189,7 +175,7 @@
     }
   }
 
-  /** Expands all dimensions. */
+  /// Expands all dimensions.
   void expandAll() {
     if (_model != null) {
       for (var value in _model.valuesForDimension(_dimensionColumnIndices[0])) {
@@ -209,13 +195,13 @@
     }
   }
 
-  /** Collapses all dimensions. */
+  /// Collapses all dimensions.
   void collapseAll() {
     _expandAllDimension = false;
     _expandedSet.clear();
   }
 
-  /** Tests if specific dimension is expanded. */
+  /// Tests if specific dimension is expanded.
   bool _isExpanded(List dimension) {
     Function eq = const ListEquality().equals;
     return _expandedSet.any((e) => eq(e, dimension));
diff --git a/packages/charted/lib/charts/data_transformers/filter_transformer.dart b/packages/charted/lib/charts/data_transformers/filter_transformer.dart
index 393c453..bc12597 100644
--- a/packages/charted/lib/charts/data_transformers/filter_transformer.dart
+++ b/packages/charted/lib/charts/data_transformers/filter_transformer.dart
@@ -1,21 +1,19 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
 typedef bool FilterFunction(dynamic value);
 
-/**
- * Transforms the ChartData base on the specified FilterDefinitions.  Each row
- * of data will be tested by passing the value at target column to the filter
- * function.  If filter function returns false, the row will be filtered out.
- * This transformer does not modify the column part of the input ChartData.
- */
+/// Transforms the ChartData base on the specified FilterDefinitions.  Each row
+/// of data will be tested by passing the value at target column to the filter
+/// function.  If filter function returns false, the row will be filtered out.
+/// This transformer does not modify the column part of the input ChartData.
 class FilterTransformer extends ChangeNotifier
     implements ChartDataTransform, ChartData {
   final SubscriptionsDisposer _dataSubscriptions = new SubscriptionsDisposer();
@@ -26,12 +24,10 @@
 
   FilterTransformer(this.filterFunctions);
 
-  /**
-   * Transforms the input data with the list of [FilterDefinition] specified in
-   * the constructor.  If the rows and columns are ObservableList in the data,
-   * changes in rows and columns in input data will trigger transform to be
-   * performed again to update the output rows and columns.
-   */
+  /// Transforms the input data with the list of [FilterDefinition] specified in
+  /// the constructor.  If the rows and columns are ObservableList in the data,
+  /// changes in rows and columns in input data will trigger transform to be
+  /// performed again to update the output rows and columns.
   ChartData transform(ChartData data) {
     _data = data;
     _registerListeners();
@@ -39,11 +35,11 @@
     return this;
   }
 
-  /** Registers listeners if data.rows or data.columns are Observable. */
+  /// Registers listeners if data.rows or data.columns are Observable.
   _registerListeners() {
     _dataSubscriptions.dispose();
 
-    if(_data is Observable) {
+    if (_data is Observable) {
       var observable = (_data as Observable);
       _dataSubscriptions.add(observable.changes.listen((records) {
         _transform();
@@ -56,18 +52,16 @@
     }
   }
 
-  /**
-   * Performs the filter transform with _data.  This is called on transform and
-   * onChange if the input ChartData is Observable.
-   */
+  /// Performs the filter transform with _data.  This is called on transform and
+  /// onChange if the input ChartData is Observable.
   _transform() {
     columns = _data.columns;
     rows.clear();
 
     for (var row in _data.rows) {
       // Add the row if each value in target column passes the filter function.
-      if (filterFunctions.every((e) =>
-          e.filterFunc(row.elementAt(e.targetColumn)))) {
+      if (filterFunctions
+          .every((e) => e.filterFunc(row.elementAt(e.targetColumn)))) {
         rows.add(row);
       }
     }
diff --git a/packages/charted/lib/charts/data_transformers/transpose_transformer.dart b/packages/charted/lib/charts/data_transformers/transpose_transformer.dart
index 2ed8e84..fcab1a0 100644
--- a/packages/charted/lib/charts/data_transformers/transpose_transformer.dart
+++ b/packages/charted/lib/charts/data_transformers/transpose_transformer.dart
@@ -1,24 +1,22 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://developers.google.com/open-source/licenses/bsd
- */
+//
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+//
 
 part of charted.charts;
 
-/**
- * Transforms the ChartData by transposing the columns and rows.  A label column
- * index in the original data will need to be specified (default to 0), all
- * values in the specified label column will be used as the label for the
- * transformed data, all the labels in the original Chart data columns will be
- * populated in the label column as values of that column.
- *
- * All values in the data except for the data in the label column must have the
- * same type; All columns except for the label column must have the same
- * formatter if a formatter exist for columns.
- */
+/// Transforms the ChartData by transposing the columns and rows.  A label column
+/// index in the original data will need to be specified (default to 0), all
+/// values in the specified label column will be used as the label for the
+/// transformed data, all the labels in the original Chart data columns will be
+/// populated in the label column as values of that column.
+///
+/// All values in the data except for the data in the label column must have the
+/// same type; All columns except for the label column must have the same
+/// formatter if a formatter exist for columns.
 class TransposeTransformer extends ChangeNotifier
     implements ChartDataTransform, ChartData {
   final SubscriptionsDisposer _dataSubscriptions = new SubscriptionsDisposer();
@@ -32,12 +30,10 @@
 
   TransposeTransformer([this._labelColumn = 0]);
 
-  /**
-   * Transforms the input data with the specified label column in the
-   * constructor.  If the ChartData is Observable, changes fired by the input
-   * data will trigger transform to be performed again to update the output rows
-   * and columns.
-   */
+  /// Transforms the input data with the specified label column in the
+  /// constructor.  If the ChartData is Observable, changes fired by the input
+  /// data will trigger transform to be performed again to update the output rows
+  /// and columns.
   ChartData transform(ChartData data) {
     _data = data;
     _registerListeners();
@@ -45,11 +41,11 @@
     return this;
   }
 
-  /** Registers listeners if input ChartData is Observable. */
+  /// Registers listeners if input ChartData is Observable.
   _registerListeners() {
     _dataSubscriptions.dispose();
 
-    if(_data is Observable) {
+    if (_data is Observable) {
       var observable = (_data as Observable);
       _dataSubscriptions.add(observable.changes.listen((records) {
         _transform();
@@ -62,10 +58,8 @@
     }
   }
 
-  /**
-   * Performs the transpose transform with _data.  This is called on transform
-   * and on changes if ChartData is Observable.
-   */
+  /// Performs the transpose transform with _data.  This is called on transform
+  /// and on changes if ChartData is Observable.
   _transform() {
     // Assert all columns are of the same type and formatter, excluding the
     // label column.
@@ -88,7 +82,8 @@
 
     columns.clear();
     rows.clear();
-    rows.addAll(new List<Iterable>.generate(_data.columns.length - 1, (i) => []));
+    rows.addAll(
+        new List<Iterable>.generate(_data.columns.length - 1, (i) => []));
 
     // Populate the transposed rows' data, excluding the label column, visit
     // each value in the original data once.
@@ -108,18 +103,19 @@
     // column that is used as the new label.
     for (var i = 0; i < rows.length; i++) {
       var columnOffset = (i < _labelColumn) ? 0 : 1;
-      (rows.elementAt(i) as List).insert(_labelColumn,
-          _data.columns.elementAt(i + columnOffset).label);
-
+      (rows.elementAt(i) as List).insert(
+          _labelColumn, _data.columns.elementAt(i + columnOffset).label);
     }
 
     // Construct new ColumnSpaces base on the label column.
     for (var label in columnLabels) {
-      columns.add(new ChartColumnSpec(type: type, label: label,
-          formatter: formatter));
+      columns.add(
+          new ChartColumnSpec(type: type, label: label, formatter: formatter));
     }
-    columns.insert(_labelColumn,
-        new ChartColumnSpec(type: ChartColumnSpec.TYPE_STRING, label:
-        _data.columns.elementAt(_labelColumn).label));
+    columns.insert(
+        _labelColumn,
+        new ChartColumnSpec(
+            type: ChartColumnSpec.TYPE_STRING,
+            label: _data.columns.elementAt(_labelColumn).label));
   }
 }
diff --git a/packages/charted/lib/charts/layout_renderers/layout_base_renderer.dart b/packages/charted/lib/charts/layout_renderers/layout_base_renderer.dart
index 2ebac9c..35bfbcc 100644
--- a/packages/charted/lib/charts/layout_renderers/layout_base_renderer.dart
+++ b/packages/charted/lib/charts/layout_renderers/layout_base_renderer.dart
@@ -117,14 +117,13 @@
     }
   }
 
-  Iterable<String> stylesForValue(int row, { bool isTail: false }) {
-    if (isTail == true) return const[];
+  Iterable<String> stylesForValue(int row, {bool isTail: false}) {
+    if (isTail == true) return const [];
     if (_valueStylesCache[row] == null) {
       if (state == null) {
-        _valueStylesCache[row] = const[];
+        _valueStylesCache[row] = const [];
       } else {
-        var styles = [],
-            flags = _valueStateCache[row];
+        var styles = [], flags = _valueStateCache[row];
 
         if (flags & ChartState.VAL_HIGHLIGHTED != 0) {
           styles.add(ChartState.VAL_HIGHLIGHTED_CLASS);
diff --git a/packages/charted/lib/charts/layout_renderers/pie_chart_renderer.dart b/packages/charted/lib/charts/layout_renderers/pie_chart_renderer.dart
index 03941d6..4409469 100644
--- a/packages/charted/lib/charts/layout_renderers/pie_chart_renderer.dart
+++ b/packages/charted/lib/charts/layout_renderers/pie_chart_renderer.dart
@@ -13,7 +13,7 @@
   static const STATS_VALUE = 'value-only';
   static const STATS_VALUE_PERCENTAGE = 'value-percentage';
 
-  final Iterable<int> dimensionsUsingBand = const[];
+  final Iterable<int> dimensionsUsingBand = const [];
   final String statsMode;
   final num innerRadiusRatio;
   final int maxSliceCount;
@@ -29,8 +29,8 @@
 
   Iterable otherRow;
 
-  PieChartRenderer({
-      num innerRadiusRatio: 0,
+  PieChartRenderer(
+      {num innerRadiusRatio: 0,
       bool showLabels,
       this.sortDataByValue: true,
       this.statsMode: STATS_PERCENTAGE,
@@ -49,8 +49,8 @@
   }
 
   @override
-  Iterable<ChartLegendItem> layout(
-      Element element, {Future schedulePostRender}) {
+  Iterable<ChartLegendItem> layout(Element element,
+      {Future schedulePostRender}) {
     _ensureReadyToDraw(element);
 
     var radius = math.min(rect.width, rect.height) / 2;
@@ -81,8 +81,7 @@
       var displayed = indices.take(maxSliceCount).toList();
       var otherItemsValue = 0;
       for (int i = displayed.length; i < indices.length; ++i) {
-        var index = indices.elementAt(i),
-            row = area.data.rows.elementAt(index);
+        var index = indices.elementAt(i), row = area.data.rows.elementAt(index);
         otherItemsValue += row == null || row.elementAt(measure) == null
             ? 0
             : row.elementAt(measure);
@@ -126,8 +125,7 @@
           ..['stroke'] = '#ffffff';
 
         e.append(
-            Namespace.createChildElement('text', e)
-              ..classes.add('pie-label'));
+            Namespace.createChildElement('text', e)..classes.add('pie-label'));
       })
       ..on('click', (d, i, e) => _event(mouseClickController, d, i, e))
       ..on('mouseover', (d, i, e) => _event(mouseOverController, d, i, e))
@@ -138,13 +136,16 @@
     _legend.clear();
     var items = new List.generate(data.length, (i) {
       SvgArcData d = data.elementAt(i);
-      Iterable row = d.data == SMALL_INT_MAX
-          ? otherRow
-          : area.data.rows.elementAt(d.data);
+      Iterable row =
+          d.data == SMALL_INT_MAX ? otherRow : area.data.rows.elementAt(d.data);
 
-      return new ChartLegendItem(index: d.data, color: colorForData(d.data, i),
-          label: row.elementAt(dimension), series: [series],
-          value: '${(((d.endAngle - d.startAngle) * 50) / math.PI).toStringAsFixed(2)}%');
+      return new ChartLegendItem(
+          index: d.data,
+          color: colorForData(d.data, i),
+          label: row.elementAt(dimension),
+          series: [series],
+          value:
+              '${(((d.endAngle - d.startAngle) * 50) / math.PI).toStringAsFixed(2)}%');
     });
     return _legend..addAll(area.config.isRTL ? items.reversed : items);
   }
@@ -176,7 +177,7 @@
   void _event(StreamController controller, data, int index, Element e) {
     // Currently, events are not supported on "Other" pie
     if (controller == null || data.data == SMALL_INT_MAX) return;
-    controller.add(new DefaultChartEventImpl(
-         scope.event, area, series, data.data, series.measures.first, data.value));
+    controller.add(new DefaultChartEventImpl(scope.event, area, series,
+        data.data, series.measures.first, data.value));
   }
 }
diff --git a/packages/charted/lib/charts/src/cartesian_area_impl.dart b/packages/charted/lib/charts/src/cartesian_area_impl.dart
index 2769f7e..8138873 100644
--- a/packages/charted/lib/charts/src/cartesian_area_impl.dart
+++ b/packages/charted/lib/charts/src/cartesian_area_impl.dart
@@ -13,22 +13,22 @@
 /// which contain two dimension axes.
 class DefaultCartesianAreaImpl implements CartesianArea {
   /// Default identifiers used by the measure axes
-  static const MEASURE_AXIS_IDS = const['_default'];
+  static const MEASURE_AXIS_IDS = const ['_default'];
 
   /// Orientations used by measure axes. First, when "x" axis is the primary
   /// and the only dimension. Second, when "y" axis is the primary and the only
   /// dimension.
-  static const MEASURE_AXIS_ORIENTATIONS = const[
-    const[ORIENTATION_LEFT, ORIENTATION_RIGHT],
-    const[ORIENTATION_BOTTOM, ORIENTATION_TOP]
+  static const MEASURE_AXIS_ORIENTATIONS = const [
+    const [ORIENTATION_LEFT, ORIENTATION_RIGHT],
+    const [ORIENTATION_BOTTOM, ORIENTATION_TOP]
   ];
 
   /// Orientations used by the dimension axes. First, when "x" is the
   /// primary dimension and the last one for cases where "y" axis is primary
   /// dimension.
-  static const DIMENSION_AXIS_ORIENTATIONS = const[
-    const[ORIENTATION_BOTTOM, ORIENTATION_LEFT],
-    const[ORIENTATION_LEFT, ORIENTATION_BOTTOM]
+  static const DIMENSION_AXIS_ORIENTATIONS = const [
+    const [ORIENTATION_BOTTOM, ORIENTATION_LEFT],
+    const [ORIENTATION_LEFT, ORIENTATION_BOTTOM]
   ];
 
   /// Mapping of measure axis Id to it's axis.
@@ -99,7 +99,8 @@
       bool autoUpdate,
       this.useTwoDimensionAxes,
       this.useRowColoring,
-      this.state) : _autoUpdate = autoUpdate {
+      this.state)
+      : _autoUpdate = autoUpdate {
     assert(host != null);
     assert(isNotInline(host));
 
@@ -194,9 +195,9 @@
   DefaultChartAxisImpl _getMeasureAxis(String axisId) {
     _measureAxes.putIfAbsent(axisId, () {
       var axisConf = config.getMeasureAxis(axisId),
-          axis = axisConf != null ?
-              new DefaultChartAxisImpl.withAxisConfig(this, axisConf) :
-                  new DefaultChartAxisImpl(this);
+          axis = axisConf != null
+              ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf)
+              : new DefaultChartAxisImpl(this);
       return axis;
     });
     return _measureAxes[axisId];
@@ -207,9 +208,9 @@
   DefaultChartAxisImpl _getDimensionAxis(int column) {
     _dimensionAxes.putIfAbsent(column, () {
       var axisConf = config.getDimensionAxis(column),
-          axis = axisConf != null ?
-              new DefaultChartAxisImpl.withAxisConfig(this, axisConf) :
-                  new DefaultChartAxisImpl(this);
+          axis = axisConf != null
+              ? new DefaultChartAxisImpl.withAxisConfig(this, axisConf)
+              : new DefaultChartAxisImpl(this);
       return axis;
     });
     return _dimensionAxes[column];
@@ -237,8 +238,7 @@
   /// Computes the size of chart and if changed from the previous time
   /// size was computed, sets attributes on svg element
   Rect _computeChartSize() {
-    int width = host.clientWidth,
-        height = host.clientHeight;
+    int width = host.clientWidth, height = host.clientHeight;
 
     if (config.minimumSize != null) {
       width = max([width, config.minimumSize.width]);
@@ -247,7 +247,9 @@
 
     AbsoluteRect padding = theme.padding;
     num paddingLeft = config.isRTL ? padding.end : padding.start;
-    Rect current = new Rect(paddingLeft, padding.top,
+    Rect current = new Rect(
+        paddingLeft,
+        padding.top,
         width - (padding.start + padding.end),
         height - (padding.top + padding.bottom));
     if (layout.chartArea == null || layout.chartArea != current) {
@@ -264,7 +266,7 @@
   }
 
   @override
-  draw({bool preRender:false, Future schedulePostRender}) {
+  draw({bool preRender: false, Future schedulePostRender}) {
     assert(data != null && config != null);
     assert(config.series != null && config.series.isNotEmpty);
 
@@ -275,9 +277,9 @@
       _svg = _scope.append('svg:svg')..classed('chart-canvas');
       if (!isNullOrEmpty(theme.filters)) {
         var element = _svg.first,
-        defs = Namespace.createChildElement('defs', element)
-          ..append(new SvgElement.svg(
-              theme.filters, treeSanitizer: new NullTreeSanitizer()));
+            defs = Namespace.createChildElement('defs', element)
+              ..append(new SvgElement.svg(theme.filters,
+                  treeSanitizer: new NullTreeSanitizer()));
         _svg.first.append(defs);
       }
 
@@ -286,17 +288,18 @@
       upperBehaviorPane = _svg.append('g')..classed('upper-render-pane');
 
       if (_behaviors.isNotEmpty) {
-        _behaviors.forEach(
-            (b) => b.init(this, upperBehaviorPane, lowerBehaviorPane));
+        _behaviors
+            .forEach((b) => b.init(this, upperBehaviorPane, lowerBehaviorPane));
       }
     }
 
     // Compute chart sizes and filter out unsupported series
     _computeChartSize();
-    var series = config.series.where((s) =>
-            _isSeriesValid(s) && s.renderer.prepare(this, s)),
-        selection = visualization.selectAll('.series-group').
-            data(series, (x) => x.hashCode),
+    var series = config.series
+            .where((s) => _isSeriesValid(s) && s.renderer.prepare(this, s)),
+        selection = visualization
+            .selectAll('.series-group')
+            .data(series, (x) => x.hashCode),
         axesDomainCompleter = new Completer();
 
     // Wait till the axes are rendered before rendering series.
@@ -314,7 +317,7 @@
         info.check();
         group.attributes['transform'] = transform;
         (s.renderer as CartesianRenderer)
-            .draw(group, schedulePostRender:schedulePostRender);
+            .draw(group, schedulePostRender: schedulePostRender);
       });
 
       // A series that was rendered earlier isn't there anymore, remove it
@@ -350,16 +353,15 @@
 
   /// Initialize the axes - required even if the axes are not being displayed.
   _initAxes({bool preRender: false}) {
-    Map measureAxisUsers = <String,Iterable<ChartSeries>>{};
+    Map measureAxisUsers = <String, Iterable<ChartSeries>>{};
 
     // Create necessary measures axes.
     // If measure axes were not configured on the series, default is used.
     _series.forEach((ChartSeries s) {
-      var measureAxisIds = isNullOrEmpty(s.measureAxisIds)
-          ? MEASURE_AXIS_IDS
-          : s.measureAxisIds;
+      var measureAxisIds =
+          isNullOrEmpty(s.measureAxisIds) ? MEASURE_AXIS_IDS : s.measureAxisIds;
       measureAxisIds.forEach((axisId) {
-        _getMeasureAxis(axisId);  // Creates axis if required
+        _getMeasureAxis(axisId); // Creates axis if required
         var users = measureAxisUsers[axisId];
         if (users == null) {
           measureAxisUsers[axisId] = [s];
@@ -402,18 +404,18 @@
     // Configure dimension axes.
     int dimensionAxesCount = useTwoDimensionAxes ? 2 : 1;
     config.dimensions.take(dimensionAxesCount).forEach((int column) {
-       var axis = _getDimensionAxis(column),
-           sampleColumnSpec = data.columns.elementAt(column),
-           values = data.rows.map((row) => row.elementAt(column)),
-           domain;
+      var axis = _getDimensionAxis(column),
+          sampleColumnSpec = data.columns.elementAt(column),
+          values = data.rows.map((row) => row.elementAt(column)),
+          domain;
 
-       if (sampleColumnSpec.useOrdinalScale) {
-         domain = values.map((e) => e.toString()).toList();
-       } else {
-         var extent = new Extent.items(values);
-         domain = [extent.min, extent.max];
-       }
-       axis.initAxisDomain(column, true, domain);
+      if (sampleColumnSpec.useOrdinalScale) {
+        domain = values.map((e) => e.toString()).toList();
+      } else {
+        var extent = new Extent.items(values);
+        domain = [extent.min, extent.max];
+      }
+      axis.initAxisDomain(column, true, domain);
     });
 
     // See if any dimensions need "band" on the axis.
@@ -421,23 +423,22 @@
     List<bool> usingBands = [false, false];
     _series.forEach((ChartSeries s) =>
         (s.renderer as CartesianRenderer).dimensionsUsingBand.forEach((x) {
-      if (x <= 1 && !(usingBands[x])) {
-        usingBands[x] = true;
-        dimensionsUsingBands.add(config.dimensions.elementAt(x));
-      }
-    }));
+          if (x <= 1 && !(usingBands[x])) {
+            usingBands[x] = true;
+            dimensionsUsingBands.add(config.dimensions.elementAt(x));
+          }
+        }));
 
     // List of measure and dimension axes that are displayed
-    assert(
-        isNullOrEmpty(config.displayedMeasureAxes) ||
+    assert(isNullOrEmpty(config.displayedMeasureAxes) ||
         config.displayedMeasureAxes.length < 2);
     var measureAxesCount = dimensionAxesCount == 1 ? 2 : 0,
         displayedMeasureAxes = (isNullOrEmpty(config.displayedMeasureAxes)
-            ? _measureAxes.keys.take(measureAxesCount)
-            : config.displayedMeasureAxes.take(measureAxesCount)).
-                toList(growable: false),
+                ? _measureAxes.keys.take(measureAxesCount)
+                : config.displayedMeasureAxes.take(measureAxesCount))
+            .toList(growable: false),
         displayedDimensionAxes =
-            config.dimensions.take(dimensionAxesCount).toList(growable: false);
+        config.dimensions.take(dimensionAxesCount).toList(growable: false);
 
     // Compute size of the dimension axes
     if (config.renderDimensionAxes != false) {
@@ -481,8 +482,9 @@
 
     // Draw the visible measure axes, if any.
     if (displayedMeasureAxes.isNotEmpty) {
-      var axisGroups = visualization.
-          selectAll('.measure-axis-group').data(displayedMeasureAxes);
+      var axisGroups = visualization
+          .selectAll('.measure-axis-group')
+          .data(displayedMeasureAxes);
       // Update measure axis (add/remove/update)
       axisGroups.enter.append('svg:g');
       axisGroups.each((axisId, index, group) {
@@ -494,8 +496,9 @@
 
     // Draw the dimension axes, unless asked not to.
     if (config.renderDimensionAxes != false) {
-      var dimAxisGroups = visualization.
-          selectAll('.dimension-axis-group').data(displayedDimensionAxes);
+      var dimAxisGroups = visualization
+          .selectAll('.dimension-axis-group')
+          .data(displayedDimensionAxes);
       // Update dimension axes (add/remove/update)
       dimAxisGroups.enter.append('svg:g');
       dimAxisGroups.each((column, index, group) {
@@ -505,15 +508,18 @@
       dimAxisGroups.exit.remove();
     } else {
       // Initialize scale on invisible axis
-      var dimensionAxisOrientations = config.isLeftAxisPrimary ?
-          DIMENSION_AXIS_ORIENTATIONS.last : DIMENSION_AXIS_ORIENTATIONS.first;
+      var dimensionAxisOrientations = config.isLeftAxisPrimary
+          ? DIMENSION_AXIS_ORIENTATIONS.last
+          : DIMENSION_AXIS_ORIENTATIONS.first;
       for (int i = 0; i < dimensionAxesCount; ++i) {
         var column = config.dimensions.elementAt(i),
             axis = _dimensionAxes[column],
             orientation = dimensionAxisOrientations[i];
-        axis.initAxisScale(orientation == ORIENTATION_LEFT ?
-            [layout.renderArea.height, 0] : [0, layout.renderArea.width]);
-      };
+        axis.initAxisScale(orientation == ORIENTATION_LEFT
+            ? [layout.renderArea.height, 0]
+            : [0, layout.renderArea.width]);
+      }
+      ;
     }
   }
 
@@ -535,21 +541,17 @@
         renderAreaWidth = layout.chartArea.width -
             (left.width + layout.axes[ORIENTATION_RIGHT].width);
 
-    layout.renderArea = new Rect(
-        left.width, top.height, renderAreaWidth, renderAreaHeight);
+    layout.renderArea =
+        new Rect(left.width, top.height, renderAreaWidth, renderAreaHeight);
 
     layout._axes
-      ..[ORIENTATION_TOP] =
-          new Rect(left.width, 0, renderAreaWidth, top.height)
-      ..[ORIENTATION_RIGHT] =
-          new Rect(left.width + renderAreaWidth, top.y,
-              right.width, renderAreaHeight)
-      ..[ORIENTATION_BOTTOM] =
-          new Rect(left.width, top.height + renderAreaHeight,
-              renderAreaWidth, bottom.height)
+      ..[ORIENTATION_TOP] = new Rect(left.width, 0, renderAreaWidth, top.height)
+      ..[ORIENTATION_RIGHT] = new Rect(
+          left.width + renderAreaWidth, top.y, right.width, renderAreaHeight)
+      ..[ORIENTATION_BOTTOM] = new Rect(left.width,
+          top.height + renderAreaHeight, renderAreaWidth, bottom.height)
       ..[ORIENTATION_LEFT] =
-          new Rect(
-              left.width, top.height, left.width, renderAreaHeight);
+          new Rect(left.width, top.height, left.width, renderAreaHeight);
   }
 
   // Updates the legend, if configuration changed since the last
@@ -562,14 +564,15 @@
     List seriesByColumn =
         new List.generate(data.columns.length, (_) => new List());
 
-    _series.forEach((s) =>
-        s.measures.forEach((m) => seriesByColumn[m].add(s)));
+    _series.forEach((s) => s.measures.forEach((m) => seriesByColumn[m].add(s)));
 
     seriesByColumn.asMap().forEach((int i, List s) {
       if (s.length == 0) return;
       legend.add(new ChartLegendItem(
-          index:i, label:data.columns.elementAt(i).label, series:s,
-          color:theme.getColorForKey(i)));
+          index: i,
+          label: data.columns.elementAt(i).label,
+          series: s,
+          color: theme.getColorForKey(i)));
     });
 
     _config.legend.update(legend, this);
@@ -578,28 +581,23 @@
 
   @override
   Stream<ChartEvent> get onMouseUp =>
-      host.onMouseUp
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+      host.onMouseUp.map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseDown =>
-      host.onMouseDown
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseDown => host.onMouseDown
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseOver =>
-      host.onMouseOver
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseOver => host.onMouseOver
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
   Stream<ChartEvent> get onMouseOut =>
-      host.onMouseOut
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+      host.onMouseOut.map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseMove =>
-      host.onMouseMove
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseMove => host.onMouseMove
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
   Stream<ChartEvent> get onValueClick {
@@ -654,11 +652,11 @@
 
 class _ChartAreaLayout implements ChartAreaLayout {
   final _axes = <String, Rect>{
-      ORIENTATION_LEFT: const Rect(),
-      ORIENTATION_RIGHT: const Rect(),
-      ORIENTATION_TOP: const Rect(),
-      ORIENTATION_BOTTOM: const Rect()
-    };
+    ORIENTATION_LEFT: const Rect(),
+    ORIENTATION_RIGHT: const Rect(),
+    ORIENTATION_TOP: const Rect(),
+    ORIENTATION_BOTTOM: const Rect()
+  };
 
   UnmodifiableMapView<String, Rect> _axesView;
 
@@ -713,7 +711,8 @@
     if (state != null) {
       var current = state.hovered;
       if (current != null &&
-          current.first == e.column && current.last == e.row) {
+          current.first == e.column &&
+          current.last == e.row) {
         state.hovered = null;
       }
     }
@@ -725,7 +724,7 @@
   check() {
     if (_renderer != _series.renderer) {
       dispose();
-      if (_series.renderer is ChartRendererBehaviorSource){
+      if (_series.renderer is ChartRendererBehaviorSource) {
         _disposer.addAll([
           _series.renderer.onValueClick.listen(_click),
           _series.renderer.onValueMouseOver.listen(_mouseOver),
@@ -736,5 +735,8 @@
     _renderer = _series.renderer;
   }
 
-  dispose() => _disposer.dispose();
+  dispose() {
+    _renderer?.dispose();
+    _disposer.dispose();
+  }
 }
diff --git a/packages/charted/lib/charts/src/chart_axis_impl.dart b/packages/charted/lib/charts/src/chart_axis_impl.dart
index 3f5d12d..345d537 100644
--- a/packages/charted/lib/charts/src/chart_axis_impl.dart
+++ b/packages/charted/lib/charts/src/chart_axis_impl.dart
@@ -55,16 +55,16 @@
     if (scale is OrdinalScale) {
       var usingBands = _area.dimensionsUsingBands.contains(_column),
           innerPadding = usingBands ? _theme.axisBandInnerPadding : 1.0,
-          outerPadding = usingBands ?
-              _theme.axisBandOuterPadding : _theme.axisOuterPadding;
+          outerPadding =
+          usingBands ? _theme.axisBandOuterPadding : _theme.axisOuterPadding;
 
       // This is because when left axis is primary the first data row should
       // appear on top of the y-axis instead of on bottom.
       if (_area.config.isLeftAxisPrimary) {
         range = range.toList().reversed;
       }
-      (scale as OrdinalScale).
-          rangeRoundBands(range, innerPadding, outerPadding);
+      (scale as OrdinalScale)
+          .rangeRoundBands(range, innerPadding, outerPadding);
     } else {
       scale.range = range;
       scale.ticksCount = _theme.axisTickCount;
@@ -97,8 +97,9 @@
       var width = textMetrics.getLongestTextWidth(formattedTicks).ceil();
       if (width > _theme.verticalAxisWidth) {
         width = _theme.verticalAxisWidth;
-        shortenedTicks = formattedTicks.map(
-            (x) => textMetrics.ellipsizeText(x, width)).toList();
+        shortenedTicks = formattedTicks
+            .map((x) => textMetrics.ellipsizeText(x, width))
+            .toList();
       }
       if (_theme.verticalAxisAutoResize) {
         size.width =
@@ -115,7 +116,7 @@
 
     var rect = _area.layout.axes[_orientation],
         renderAreaRect = _area.layout.renderArea,
-        range =  _isVertical ? [rect.height, 0] : [0, rect.width],
+        range = _isVertical ? [rect.height, 0] : [0, rect.width],
         innerTickSize = _theme.axisTickSize <= ChartAxisTheme.FILL_RENDER_AREA
             ? 0 - (_isVertical ? renderAreaRect.width : renderAreaRect.height)
             : _theme.axisTickSize,
@@ -126,24 +127,25 @@
     element.attributes['transform'] = 'translate(${rect.x}, ${rect.y})';
 
     if (!_isVertical) {
-      _axisTicksPlacement =
-          new RotateHorizontalAxisTicks(rect,
-              _theme.ticksFont, _theme.axisTickSize + _theme.axisTickPadding);
+      _axisTicksPlacement = new RotateHorizontalAxisTicks(
+          rect, _theme.ticksFont, _theme.axisTickSize + _theme.axisTickPadding);
     }
 
     initAxisScale(range);
-    var axis = new SvgAxis(orientation: _orientation,
-        innerTickSize: innerTickSize, outerTickSize: 0,
+    var axis = new SvgAxis(
+        orientation: _orientation,
+        innerTickSize: innerTickSize,
+        outerTickSize: 0,
         tickPadding: _theme.axisTickPadding,
-        tickFormat: _columnSpec.formatter, tickValues: tickValues,
+        tickFormat: _columnSpec.formatter,
+        tickValues: tickValues,
         scale: scale);
 
     axis.create(element, scope,
         axisTicksBuilder: _axisTicksPlacement, isRTL: _area.config.isRTL);
   }
 
-  void clear() {
-  }
+  void clear() {}
 
   // Scale passed through configuration takes precedence
   Scale get scale =>
@@ -175,8 +177,7 @@
   RotateHorizontalAxisTicks(this.rect, this.ticksFont, this.tickLineLength);
 
   void init(SvgAxis axis) {
-    assert(
-        axis.orientation == ORIENTATION_BOTTOM ||
+    assert(axis.orientation == ORIENTATION_BOTTOM ||
         axis.orientation == ORIENTATION_TOP);
     assert(ticksFont != null);
     ticks = axis.tickValues;
@@ -190,16 +191,16 @@
 
     // Check if we need rotation
     if (0.90 * allowedWidth < maxLabelWidth) {
-      var rectHeight = tickLineLength > 0
-          ? rect.height - tickLineLength
-          : rect.height;
+      var rectHeight =
+          tickLineLength > 0 ? rect.height - tickLineLength : rect.height;
       rotation = 45;
 
       // Check if we have enough space to render full chart
       allowedWidth = (1.4142 * (rectHeight)) - (textMetrics.fontSize / 1.4142);
       if (maxLabelWidth > allowedWidth) {
-        shortenedTicks = formattedTicks.map(
-            (x) => textMetrics.ellipsizeText(x, allowedWidth)).toList();
+        shortenedTicks = formattedTicks
+            .map((x) => textMetrics.ellipsizeText(x, allowedWidth))
+            .toList();
       }
     }
   }
diff --git a/packages/charted/lib/charts/src/chart_config_impl.dart b/packages/charted/lib/charts/src/chart_config_impl.dart
index e77057c..640d23f 100644
--- a/packages/charted/lib/charts/src/chart_config_impl.dart
+++ b/packages/charted/lib/charts/src/chart_config_impl.dart
@@ -9,8 +9,8 @@
 part of charted.charts;
 
 class DefaultChartConfigImpl extends ChangeNotifier implements ChartConfig {
-  final Map<String,ChartAxisConfig> _measureAxisRegistry = {};
-  final Map<int,ChartAxisConfig> _dimensionAxisRegistry = {};
+  final Map<String, ChartAxisConfig> _measureAxisRegistry = {};
+  final Map<int, ChartAxisConfig> _dimensionAxisRegistry = {};
   final SubscriptionsDisposer _disposer = new SubscriptionsDisposer();
 
   bool _isRTL = false;
@@ -39,7 +39,8 @@
   @override
   bool switchAxesForRTL = true;
 
-  DefaultChartConfigImpl(Iterable<ChartSeries> series, Iterable<int> dimensions) {
+  DefaultChartConfigImpl(
+      Iterable<ChartSeries> series, Iterable<int> dimensions) {
     this.series = series;
     this.dimensions = dimensions;
   }
@@ -55,8 +56,10 @@
     // Monitor each series for changes on them
     values.forEach((item) {
       if (item is Observable) {
-        _disposer.add(item.changes.listen(
-                (_) => notifyChange(const ChartConfigChangeRecord())), item);
+        _disposer.add(
+            item.changes
+                .listen((_) => notifyChange(const ChartConfigChangeRecord())),
+            item);
       }
     });
 
@@ -69,8 +72,8 @@
           record.removed.forEach((value) => _disposer.unsubscribe(value));
           for (int i = 0; i < record.addedCount; i++) {
             var added = observable[i + record.index];
-            _disposer.add(added.changes.listen(
-                (_) => notifyChange(const ChartConfigChangeRecord())));
+            _disposer.add(added.changes
+                .listen((_) => notifyChange(const ChartConfigChangeRecord())));
           }
         });
         notifyChange(const ChartConfigChangeRecord());
@@ -93,9 +96,9 @@
     if (values == null || values.isEmpty) return;
 
     if (_dimensions is ObservableList) {
-      _dimensionsSubscription =
-          (_dimensions as ObservableList).listChanges.listen(
-              (_) => notifyChange(const ChartConfigChangeRecord()));
+      _dimensionsSubscription = (_dimensions as ObservableList)
+          .listChanges
+          .listen((_) => notifyChange(const ChartConfigChangeRecord()));
     }
   }
 
diff --git a/packages/charted/lib/charts/src/chart_data_impl.dart b/packages/charted/lib/charts/src/chart_data_impl.dart
index 9a62f1d..dff6f5c 100644
--- a/packages/charted/lib/charts/src/chart_data_impl.dart
+++ b/packages/charted/lib/charts/src/chart_data_impl.dart
@@ -15,7 +15,8 @@
   bool _hasObservableRows = false;
   SubscriptionsDisposer _disposer = new SubscriptionsDisposer();
 
-  DefaultChartDataImpl(Iterable<ChartColumnSpec> columns, Iterable<Iterable> rows) {
+  DefaultChartDataImpl(
+      Iterable<ChartColumnSpec> columns, Iterable<Iterable> rows) {
     this.columns = columns;
     this.rows = rows;
   }
@@ -36,17 +37,18 @@
 
     _rows = value;
     if (_rows is ObservableList) {
-      _disposer.add(
-          (_rows as ObservableList).listChanges.listen(rowsChanged));
+      _disposer.add((_rows as ObservableList).listChanges.listen(rowsChanged));
     }
 
     if (_rows.every((row) => row is ObservableList)) {
       _hasObservableRows = true;
       for (int i = 0; i < _rows.length; i++) {
         var row = _rows.elementAt(i);
-        _disposer.add(row.listChanges.listen((changes)
-            => _valuesChanged(i, changes)), row);
-      };
+        _disposer.add(
+            row.listChanges.listen((changes) => _valuesChanged(i, changes)),
+            row);
+      }
+      ;
     } else if (_rows is Observable) {
       logger.info('List of rows is Observable, but not rows themselves!');
     }
@@ -62,16 +64,17 @@
     changes.forEach((ListChangeRecord change) {
       change.removed.forEach((item) => _disposer.unsubscribe(item));
 
-      for(int i = 0; i < change.addedCount; i++) {
-        var index = change.index + i,
-            row = _rows.elementAt(index);
+      for (int i = 0; i < change.addedCount; i++) {
+        var index = change.index + i, row = _rows.elementAt(index);
 
         if (row is! ObservableList) {
           logger.severe('A non-observable row was added! '
               'Changes on this row will not be monitored');
         } else {
-          _disposer.add(row.listChanges.listen((changes)
-              => _valuesChanged(index, changes)), row);
+          _disposer.add(
+              row.listChanges
+                  .listen((changes) => _valuesChanged(index, changes)),
+              row);
         }
       }
     });
@@ -98,7 +101,7 @@
       }
     }
 
-    var totalLength = 1;  // 1 for the leading '|'.
+    var totalLength = 1; // 1 for the leading '|'.
     for (var length in cellDataLength) {
       // 3 for the leading and trailing ' ' padding and trailing '|'.
       totalLength += length + 3;
diff --git a/packages/charted/lib/charts/src/chart_events_impl.dart b/packages/charted/lib/charts/src/chart_events_impl.dart
index 6e2c258..9bb8d1e 100644
--- a/packages/charted/lib/charts/src/chart_events_impl.dart
+++ b/packages/charted/lib/charts/src/chart_events_impl.dart
@@ -36,9 +36,8 @@
   DefaultChartEventImpl(this.source, this.area,
       [this.series, this.row, this.column, this.value]) {
     var hostRect = area.host.getBoundingClientRect(),
-        left = area.config.isRTL
-            ? area.theme.padding.end
-            : area.theme.padding.start;
+        left =
+        area.config.isRTL ? area.theme.padding.end : area.theme.padding.start;
     if (source != null) {
       chartX = source.client.x - hostRect.left - left;
       chartY = source.client.y - hostRect.top - area.theme.padding.top;
diff --git a/packages/charted/lib/charts/src/chart_legend_impl.dart b/packages/charted/lib/charts/src/chart_legend_impl.dart
index 37778e1..dfefbc4 100644
--- a/packages/charted/lib/charts/src/chart_legend_impl.dart
+++ b/packages/charted/lib/charts/src/chart_legend_impl.dart
@@ -100,7 +100,7 @@
     var tooltip = _root.select('.chart-legend-more-tooltip');
     if (tooltip.isEmpty) {
       tooltip = _root.select('.chart-legend-more').append('div')
-          ..classed('chart-legend-more-tooltip');
+        ..classed('chart-legend-more-tooltip');
     }
     tooltip.style('opacity', '1');
 
@@ -110,8 +110,8 @@
   /// Creates legend items starting at the given index.
   void _createLegendItems() {
     var state = _area.state,
-        rows = _root.selectAll(
-            '.chart-legend-row').data(_items, (x) => x.hashCode),
+        rows =
+        _root.selectAll('.chart-legend-row').data(_items, (x) => x.hashCode),
         isFirstRender = rows.length == 0;
 
     var enter = rows.enter.appendWithCallback((d, i, e) {
@@ -120,8 +120,10 @@
             ..className = 'chart-legend-color',
           label = Namespace.createChildElement('div', e)
             ..className = 'chart-legend-label',
-          value = showValues ? (Namespace.createChildElement('div', e)
-            ..className = 'chart-legend-value') : null;
+          value = showValues
+              ? (Namespace.createChildElement('div', e)
+                ..className = 'chart-legend-value')
+              : null;
 
       var rowStyles = ['chart-legend-row'].toList();
 
@@ -136,8 +138,8 @@
             rowStyles.add('chart-legend-selected');
           }
         }
-        rowStyles.addAll(
-            d.series.map((ChartSeries x) => 'type-${x.renderer.name}'));
+        rowStyles
+            .addAll(d.series.map((ChartSeries x) => 'type-${x.renderer.name}'));
 
         color.style.setProperty('background-color', d.color);
         row.append(color);
@@ -186,17 +188,17 @@
       enter
         ..on('mouseover', (d, i, e) => state.preview = d.index)
         ..on('mouseout', (d, i, e) {
-            if (state.preview == d.index) {
-              state.preview = null;
-            }
-          })
+          if (state.preview == d.index) {
+            state.preview = null;
+          }
+        })
         ..on('click', (d, i, e) {
-            if (state.isSelected(d.index)) {
-              state.unselect(d.index);
-            } else {
-              state.select(d.index);
-            }
-          });
+          if (state.isSelected(d.index)) {
+            state.unselect(d.index);
+          } else {
+            state.select(d.index);
+          }
+        });
     }
 
     rows.exit.remove();
diff --git a/packages/charted/lib/charts/src/chart_state_impl.dart b/packages/charted/lib/charts/src/chart_state_impl.dart
index 71c4afa..44f5d74 100644
--- a/packages/charted/lib/charts/src/chart_state_impl.dart
+++ b/packages/charted/lib/charts/src/chart_state_impl.dart
@@ -26,21 +26,22 @@
   LinkedHashSet<int> hidden = new LinkedHashSet<int>();
 
   LinkedHashSet<int> selection = new LinkedHashSet<int>();
-  LinkedHashSet<Pair<int,int>> highlights = new LinkedHashSet<Pair<int,int>>();
+  LinkedHashSet<Pair<int, int>> highlights =
+      new LinkedHashSet<Pair<int, int>>();
 
-  Pair<int,int> _hovered;
+  Pair<int, int> _hovered;
   int _preview;
 
-  DefaultChartStateImpl({
-    this.supportColumnSelection: true,
-    this.supportColumnPreview: true,
-    this.supportValueHighlight: true,
-    this.supportValueHover: true,
-    this.isMultiSelect: false,
-    this.isMultiHighlight: false,
-    this.isSelectOrHighlight: true});
+  DefaultChartStateImpl(
+      {this.supportColumnSelection: true,
+      this.supportColumnPreview: true,
+      this.supportValueHighlight: true,
+      this.supportValueHover: true,
+      this.isMultiSelect: false,
+      this.isMultiHighlight: false,
+      this.isSelectOrHighlight: true});
 
-  set hovered(Pair<int,int> value) {
+  set hovered(Pair<int, int> value) {
     if (!this.supportValueHover) return null;
     if (value != _hovered) {
       _hovered = value;
@@ -48,7 +49,8 @@
     }
     return value;
   }
-  Pair<int,int> get hovered => _hovered;
+
+  Pair<int, int> get hovered => _hovered;
 
   set preview(int value) {
     if (!this.supportColumnPreview) return null;
@@ -58,12 +60,13 @@
     }
     return value;
   }
+
   int get preview => _preview;
 
   bool unhide(int id) {
     if (hidden.contains(id)) {
       hidden.remove(id);
-      notifyChange(new ChartVisibilityChangeRecord(unhide:id));
+      notifyChange(new ChartVisibilityChangeRecord(unhide: id));
     }
     return true;
   }
@@ -71,7 +74,7 @@
   bool hide(int id) {
     if (!hidden.contains(id)) {
       hidden.add(id);
-      notifyChange(new ChartVisibilityChangeRecord(hide:id));
+      notifyChange(new ChartVisibilityChangeRecord(hide: id));
     }
     return false;
   }
@@ -88,7 +91,7 @@
         highlights.clear();
       }
       selection.add(id);
-      notifyChange(new ChartSelectionChangeRecord(add:id));
+      notifyChange(new ChartSelectionChangeRecord(add: id));
     }
     return true;
   }
@@ -96,7 +99,7 @@
   bool unselect(int id) {
     if (selection.contains(id)) {
       selection.remove(id);
-      notifyChange(new ChartSelectionChangeRecord(remove:id));
+      notifyChange(new ChartSelectionChangeRecord(remove: id));
     }
     return false;
   }
diff --git a/packages/charted/lib/charts/src/layout_area_impl.dart b/packages/charted/lib/charts/src/layout_area_impl.dart
index cc4de21..d4bbaef 100644
--- a/packages/charted/lib/charts/src/layout_area_impl.dart
+++ b/packages/charted/lib/charts/src/layout_area_impl.dart
@@ -60,12 +60,8 @@
   StreamController<ChartEvent> _valueMouseOutController;
   StreamController<ChartEvent> _valueMouseClickController;
 
-  DefaultLayoutAreaImpl(
-      this.host,
-      ChartData data,
-      ChartConfig config,
-      this._autoUpdate,
-      this.state) {
+  DefaultLayoutAreaImpl(this.host, ChartData data, ChartConfig config,
+      this._autoUpdate, this.state) {
     assert(host != null);
     assert(isNotInline(host));
 
@@ -139,8 +135,7 @@
   /// Computes the size of chart and if changed from the previous time
   /// size was computed, sets attributes on svg element
   Rect _computeChartSize() {
-    int width = host.clientWidth,
-        height = host.clientHeight;
+    int width = host.clientWidth, height = host.clientHeight;
 
     if (config.minimumSize != null) {
       width = max([width, config.minimumSize.width]);
@@ -149,7 +144,9 @@
 
     AbsoluteRect padding = theme.padding;
     num paddingLeft = config.isRTL ? padding.end : padding.start;
-    Rect current = new Rect(paddingLeft, padding.top,
+    Rect current = new Rect(
+        paddingLeft,
+        padding.top,
         width - (padding.start + padding.end),
         height - (padding.top + padding.bottom));
     if (layout.chartArea == null || layout.chartArea != current) {
@@ -170,7 +167,7 @@
   }
 
   @override
-  draw({bool preRender:false, Future schedulePostRender}) {
+  draw({bool preRender: false, Future schedulePostRender}) {
     assert(data != null && config != null);
     assert(config.series != null && config.series.isNotEmpty);
 
@@ -185,15 +182,15 @@
       upperBehaviorPane = _svg.append('g')..classed('upper-render-pane');
 
       if (_behaviors.isNotEmpty) {
-        _behaviors.forEach(
-            (b) => b.init(this, upperBehaviorPane, lowerBehaviorPane));
+        _behaviors
+            .forEach((b) => b.init(this, upperBehaviorPane, lowerBehaviorPane));
       }
     }
 
     // Compute chart sizes and filter out unsupported series
     _computeChartSize();
-    var series = config.series.firstWhere(
-            (s) => s.renderer.prepare(this, s), orElse: () => null),
+    var series = config.series
+            .firstWhere((s) => s.renderer.prepare(this, s), orElse: () => null),
         group = visualization.first.querySelector('.series-group');
 
     // We need atleast one matching series.
@@ -202,7 +199,7 @@
     // Create a group for rendering, if it was not already done.
     if (group == null) {
       group = Namespace.createChildElement('g', visualization.first)
-          ..classes.add('series-group');
+        ..classes.add('series-group');
       visualization.first.append(group);
     }
 
@@ -250,7 +247,7 @@
     }
 
     Iterable<ChartLegendItem> legend =
-        _renderer.layout(group, schedulePostRender:schedulePostRender);
+        _renderer.layout(group, schedulePostRender: schedulePostRender);
 
     // Notify on the stream that the chart has been updated.
     isReady = true;
@@ -259,33 +256,30 @@
     _series = series;
 
     // Updates the legend if required.
-    _config.legend.update(legend, this);
+    if (_config.legend != null) {
+      _config.legend.update(legend, this);
+    }
   }
 
   @override
   Stream<ChartEvent> get onMouseUp =>
-      host.onMouseUp
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+      host.onMouseUp.map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseDown =>
-      host.onMouseDown
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseDown => host.onMouseDown
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseOver =>
-      host.onMouseOver
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseOver => host.onMouseOver
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
   Stream<ChartEvent> get onMouseOut =>
-      host.onMouseOut
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+      host.onMouseOut.map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
-  Stream<ChartEvent> get onMouseMove =>
-      host.onMouseMove
-          .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
+  Stream<ChartEvent> get onMouseMove => host.onMouseMove
+      .map((MouseEvent e) => new DefaultChartEventImpl(e, this));
 
   @override
   Stream<ChartEvent> get onValueClick {
diff --git a/packages/charted/lib/charts/themes/quantum_theme.dart b/packages/charted/lib/charts/themes/quantum_theme.dart
index a8cf063..127e78a 100644
--- a/packages/charted/lib/charts/themes/quantum_theme.dart
+++ b/packages/charted/lib/charts/themes/quantum_theme.dart
@@ -9,33 +9,32 @@
 part of charted.charts;
 
 class QuantumChartTheme extends ChartTheme {
-  static const List OTHER_COLORS =
-      const['#EEEEEE', '#BDBDBD', '#9E9E9E'];
+  static const List OTHER_COLORS = const ['#EEEEEE', '#BDBDBD', '#9E9E9E'];
 
-  static const List<List<String>> COLORS = const[
-    const [ '#C5D9FB', '#4184F3', '#2955C5' ],
-    const [ '#F3C6C2', '#DB4437', '#A52714' ],
-    const [ '#FBE7B1', '#F4B400', '#EF9200' ],
-    const [ '#B6E0CC', '#0F9D58', '#0A7F42' ],
-    const [ '#E0BDE6', '#AA46BB', '#691A99' ],
-    const [ '#B1EAF1', '#00ABC0', '#00828E' ],
-    const [ '#FFCBBB', '#FF6F42', '#E54918' ],
-    const [ '#EFF3C2', '#9D9C23', '#817616' ],
-    const [ '#C4C9E8', '#5B6ABF', '#3848AA' ],
-    const [ '#F7BACF', '#EF6191', '#E81D62' ],
-    const [ '#B1DEDA', '#00786A', '#004C3F' ],
-    const [ '#F38EB0', '#C1175A', '#870D4E' ],
+  static const List<List<String>> COLORS = const [
+    const ['#C5D9FB', '#4184F3', '#2955C5'],
+    const ['#F3C6C2', '#DB4437', '#A52714'],
+    const ['#FBE7B1', '#F4B400', '#EF9200'],
+    const ['#B6E0CC', '#0F9D58', '#0A7F42'],
+    const ['#E0BDE6', '#AA46BB', '#691A99'],
+    const ['#B1EAF1', '#00ABC0', '#00828E'],
+    const ['#FFCBBB', '#FF6F42', '#E54918'],
+    const ['#EFF3C2', '#9D9C23', '#817616'],
+    const ['#C4C9E8', '#5B6ABF', '#3848AA'],
+    const ['#F7BACF', '#EF6191', '#E81D62'],
+    const ['#B1DEDA', '#00786A', '#004C3F'],
+    const ['#F38EB0', '#C1175A', '#870D4E'],
   ];
 
-  static const List<List<String>> COLORS_ASSIST = const[
-    const [ '#C5D9FB', '#4184F3', '#2955C5' ],
-    const [ '#F3C6C2', '#DB4437', '#A52714' ],
-    const [ '#FBE7B1', '#F4B400', '#EF9200' ],
-    const [ '#B6E0CC', '#0F9D58', '#0A7F42' ],
-    const [ '#E0BDE6', '#AA46BB', '#691A99' ],
-    const [ '#B1EAF1', '#00ABC0', '#00828E' ],
-    const [ '#FFCBBB', '#FF6F42', '#E54918' ],
-    const [ '#EFF3C2', '#9D9C23', '#817616' ]
+  static const List<List<String>> COLORS_ASSIST = const [
+    const ['#C5D9FB', '#4184F3', '#2955C5'],
+    const ['#F3C6C2', '#DB4437', '#A52714'],
+    const ['#FBE7B1', '#F4B400', '#EF9200'],
+    const ['#B6E0CC', '#0F9D58', '#0A7F42'],
+    const ['#E0BDE6', '#AA46BB', '#691A99'],
+    const ['#B1EAF1', '#00ABC0', '#00828E'],
+    const ['#FFCBBB', '#FF6F42', '#E54918'],
+    const ['#EFF3C2', '#9D9C23', '#817616']
   ];
 
   final OrdinalScale _scale = new OrdinalScale()..range = COLORS;
@@ -64,19 +63,15 @@
   }
 
   @override
-  String getFilterForState(int state) =>
-      state & ChartState.COL_PREVIEW != 0 ||
+  String getFilterForState(int state) => state & ChartState.COL_PREVIEW != 0 ||
       state & ChartState.VAL_HOVERED != 0 ||
       state & ChartState.COL_SELECTED != 0 ||
-      state & ChartState.VAL_HIGHLIGHTED != 0
-          ? 'url(#drop-shadow)'
-          : '';
+      state & ChartState.VAL_HIGHLIGHTED != 0 ? 'url(#drop-shadow)' : '';
 
   @override
-  String getOtherColor([int state = 0]) =>
-      OTHER_COLORS is Iterable
-          ? colorForState(OTHER_COLORS, state)
-          : OTHER_COLORS;
+  String getOtherColor([int state = 0]) => OTHER_COLORS is Iterable
+      ? colorForState(OTHER_COLORS, state)
+      : OTHER_COLORS;
 
   @override
   ChartAxisTheme getMeasureAxisTheme([Scale _]) =>
diff --git a/packages/charted/lib/core/interpolators.dart b/packages/charted/lib/core/interpolators.dart
index 0626a6f..9ad174a 100644
--- a/packages/charted/lib/core/interpolators.dart
+++ b/packages/charted/lib/core/interpolators.dart
@@ -7,12 +7,12 @@
 //
 
 /// A collection of interpolator generators and easing functions.
-/// 
+///
 /// Interpolators provide intermediate state when transitioning from one
 /// frame to another in an animation.
-/// 
-/// Easing functions indicate progress of an animation to interpolators. 
-/// 
+///
+/// Easing functions indicate progress of an animation to interpolators.
+///
 /// Currently provides interpolator for various types, including basic types
 /// like numbers, colors, strings, transforms and for iterables.
 library charted.core.interpolators;
diff --git a/packages/charted/lib/core/interpolators/easing.dart b/packages/charted/lib/core/interpolators/easing.dart
index 2b4bdec..e80bbd6 100644
--- a/packages/charted/lib/core/interpolators/easing.dart
+++ b/packages/charted/lib/core/interpolators/easing.dart
@@ -8,21 +8,21 @@
 
 part of charted.core.interpolators;
 
-const String EASE_TYPE_LINEAR   = 'linear';
-const String EASE_TYPE_POLY     = 'poly';
-const String EASE_TYPE_QUAD     = 'quad';
-const String EASE_TYPE_CUBIC    = 'cubic';
-const String EASE_TYPE_SIN      = 'sin';
-const String EASE_TYPE_EXP      = 'exp';
-const String EASE_TYPE_CIRCLE   = 'circle';
-const String EASE_TYPE_ELASTIC  = 'elastic';
-const String EASE_TYPE_BACK     = 'back';
-const String EASE_TYPE_BOUNCE   = 'bounce';
+const String EASE_TYPE_LINEAR = 'linear';
+const String EASE_TYPE_POLY = 'poly';
+const String EASE_TYPE_QUAD = 'quad';
+const String EASE_TYPE_CUBIC = 'cubic';
+const String EASE_TYPE_SIN = 'sin';
+const String EASE_TYPE_EXP = 'exp';
+const String EASE_TYPE_CIRCLE = 'circle';
+const String EASE_TYPE_ELASTIC = 'elastic';
+const String EASE_TYPE_BACK = 'back';
+const String EASE_TYPE_BOUNCE = 'bounce';
 
-const String EASE_MODE_IN       = 'in';
-const String EASE_MODE_OUT      = 'out';
-const String EASE_MODE_IN_OUT   = 'in-out';
-const String EASE_MODE_OUT_IN   = 'out-in';
+const String EASE_MODE_IN = 'in';
+const String EASE_MODE_OUT = 'out';
+const String EASE_MODE_IN_OUT = 'in-out';
+const String EASE_MODE_OUT_IN = 'out-in';
 
 /// [EasingFunction] manipulates progression of an animation.  The returned
 /// value is passed to an [Interpolator] to generate intermediate state.
@@ -33,8 +33,8 @@
 typedef EasingFunction EasingModeFunction(EasingFunction fn);
 
 /// Creates an easing function based on type and mode.
-EasingFunction easingFunctionByName(
-    String type, [String mode = EASE_MODE_IN, List params]) {
+EasingFunction easingFunctionByName(String type,
+    [String mode = EASE_MODE_IN, List params]) {
   const Map easingTypes = const {
     EASE_TYPE_LINEAR: identityFunction,
     EASE_TYPE_POLY: easePoly,
@@ -47,21 +47,21 @@
     EASE_TYPE_BACK: easeBack,
     EASE_TYPE_BOUNCE: easeBounce
   };
-  
+
   const Map easingModes = const {
     EASE_MODE_IN: identityFunction,
     EASE_MODE_OUT: reverseEasingFn,
     EASE_MODE_IN_OUT: reflectEasingFn,
     EASE_MODE_OUT_IN: reflectReverseEasingFn
   };
-  
+
   const Map customEasingFunctions = const {
-    '$EASE_TYPE_CUBIC-$EASE_MODE_IN_OUT': easeCubicInOut 
+    '$EASE_TYPE_CUBIC-$EASE_MODE_IN_OUT': easeCubicInOut
   };
 
   assert(easingTypes.containsKey(type));
   assert(easingModes.containsKey(mode));
-  
+
   EasingFunction fn;
   if (customEasingFunctions.containsKey('$type-$mode')) {
     fn = Function.apply(customEasingFunctions['$type-$mode'], params);
@@ -72,18 +72,15 @@
   return clampEasingFn(fn);
 }
 
-
 /// Clamps transition progress to stay between 0.0 and 1.0
 EasingFunction clampEasingFn(EasingFunction f) =>
     (t) => t <= 0 ? 0 : t >= 1 ? 1 : f(t);
 
-
 //
 // Implementation of easing modes.
 //
 
-EasingFunction reverseEasingFn(EasingFunction f) =>
-    (t) => 1 - f(1 - t);
+EasingFunction reverseEasingFn(EasingFunction f) => (t) => 1 - f(1 - t);
 
 EasingFunction reflectEasingFn(EasingFunction f) =>
     (t) => .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
@@ -91,7 +88,6 @@
 EasingFunction reflectReverseEasingFn(EasingFunction f) =>
     reflectEasingFn(reverseEasingFn(f));
 
-
 //
 // Implementation of easing function generators.
 //
@@ -100,38 +96,33 @@
 
 EasingFunction easeElastic([a = 1, p = 0.45]) {
   var s = p / 2 * math.PI * math.asin(1 / a);
-  return (t) => 1 + a * math.pow(2, -10 * t) *
-      math.sin((t - s) * 2 * math.PI / p);
+  return (t) =>
+      1 + a * math.pow(2, -10 * t) * math.sin((t - s) * 2 * math.PI / p);
 }
 
-EasingFunction easeBack([s = 1.70158]) =>
-    (num t) => t * t * ((s + 1) * t - s);
+EasingFunction easeBack([s = 1.70158]) => (num t) => t * t * ((s + 1) * t - s);
 
 EasingFunction easeQuad() => (num t) => t * t;
 
 EasingFunction easeCubic() => (num t) => t * t * t;
 
-EasingFunction easeCubicInOut() =>
-    (num t) {
+EasingFunction easeCubicInOut() => (num t) {
       if (t <= 0) return 0;
       if (t >= 1) return 1;
-      var t2 = t * t,
-          t3 = t2 * t;
+      var t2 = t * t, t3 = t2 * t;
       return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
     };
 
-EasingFunction easeSin() =>
-    (num t) => 1 - math.cos(t * math.PI / 2);
+EasingFunction easeSin() => (num t) => 1 - math.cos(t * math.PI / 2);
 
-EasingFunction easeExp() =>
-    (num t) => math.pow(2, 10 * (t - 1));
+EasingFunction easeExp() => (num t) => math.pow(2, 10 * (t - 1));
 
-EasingFunction easeCircle() =>
-    (num t) => 1 - math.sqrt(1 - t * t);
+EasingFunction easeCircle() => (num t) => 1 - math.sqrt(1 - t * t);
 
-EasingFunction easeBounce() =>
-    (num t) =>  t < 1 / 2.75 ?
-        7.5625 * t * t : t < 2 / 2.75 ?
-            7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ?
-                7.5625 * (t -= 2.25 / 2.75) * t + .9375
-                    : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
+EasingFunction easeBounce() => (num t) => t < 1 / 2.75
+    ? 7.5625 * t * t
+    : t < 2 / 2.75
+        ? 7.5625 * (t -= 1.5 / 2.75) * t + .75
+        : t < 2.5 / 2.75
+            ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375
+            : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
diff --git a/packages/charted/lib/core/interpolators/interpolators.dart b/packages/charted/lib/core/interpolators/interpolators.dart
index 0de80ee..56dc9df 100644
--- a/packages/charted/lib/core/interpolators/interpolators.dart
+++ b/packages/charted/lib/core/interpolators/interpolators.dart
@@ -19,7 +19,7 @@
 /// List of registered interpolators - [createInterpolatorFromRegistry]
 /// iterates through this list from backwards and the first non-null
 /// interpolate function is returned to the caller.
-List<InterpolatorGenerator> _interpolators = [ createInterpolatorByType ];
+List<InterpolatorGenerator> _interpolators = [createInterpolatorByType];
 
 /// Returns a default interpolator between values [a] and [b]. Unless
 /// more interpolators are added, one of the internal implementations are
@@ -33,18 +33,21 @@
 }
 
 /// Creates an interpolator based on the type of [a] and [b].
-/// 
+///
 /// Usage note: Use this method only when type of [a] and [b] are not known.
 ///     When used, this function will prevent tree shaking of all built-in
 ///     interpolators.
-Interpolator createInterpolatorByType(a, b) =>
-    (a is List && b is List) ? createListInterpolator(a, b) :
-    (a is Map && b is Map) ? createMapInterpolator(a, b) :
-    (a is String && b is String) ? createStringInterpolator(a, b) :
-    (a is num && b is num) ? createNumberInterpolator(a, b) :
-    (a is Color && b is Color) ? createRgbColorInterpolator(a, b) :
-    (t) => (t <= 0.5) ? a : b;
-
+Interpolator createInterpolatorByType(a, b) => (a is List && b is List)
+    ? createListInterpolator(a, b)
+    : (a is Map && b is Map)
+        ? createMapInterpolator(a, b)
+        : (a is String && b is String)
+            ? createStringInterpolator(a, b)
+            : (a is num && b is num)
+                ? createNumberInterpolator(a, b)
+                : (a is Color && b is Color)
+                    ? createRgbColorInterpolator(a, b)
+                    : (t) => (t <= 0.5) ? a : b;
 
 //
 // Implementations of InterpolatorGenerator
@@ -62,7 +65,6 @@
   return (t) => (a + b * t).round();
 }
 
-
 /// Generate an interpolator between two strings [a] and [b].
 ///
 /// The interpolator will interpolate all the number pairs in both strings
@@ -87,9 +89,8 @@
     return createHslColorInterpolator(
         new Color.fromHslString(a), new Color.fromHslString(b));
   }
-  
-  var numberRegEx =
-          new RegExp(r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?'),
+
+  var numberRegEx = new RegExp(r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?'),
       numMatchesInA = numberRegEx.allMatches(a),
       numMatchesInB = numberRegEx.allMatches(b),
       stringParts = [],
@@ -111,13 +112,13 @@
   int numberLength = math.min(numberPartsInA.length, numberPartsInB.length);
   int maxLength = math.max(numberPartsInA.length, numberPartsInB.length);
   for (var i = 0; i < numberLength; i++) {
-    interpolators.add(createNumberInterpolator(num.parse(numberPartsInA[i]),
-        num.parse(numberPartsInB[i])));
+    interpolators.add(createNumberInterpolator(
+        num.parse(numberPartsInA[i]), num.parse(numberPartsInB[i])));
   }
   if (numberPartsInA.length < numberPartsInB.length) {
     for (var i = numberLength; i < maxLength; i++) {
-      interpolators.add(createNumberInterpolator(num.parse(numberPartsInB[i]),
-        num.parse(numberPartsInB[i])));
+      interpolators.add(createNumberInterpolator(
+          num.parse(numberPartsInB[i]), num.parse(numberPartsInB[i])));
     }
   }
 
@@ -136,29 +137,19 @@
 /// Generate an interpolator for RGB values.
 Interpolator createRgbColorInterpolator(Color a, Color b) {
   if (a == null || b == null) return (t) => b;
-  var ar = a.r,
-      ag = a.g,
-      ab = a.b,
-      br = b.r - ar,
-      bg = b.g - ag,
-      bb = b.b - ab;
+  var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
 
-  return (t) => new Color.fromRgba((ar + br * t).round(),
-      (ag + bg * t).round(), (ab + bb * t).round(), 1.0).toRgbaString();
+  return (t) => new Color.fromRgba((ar + br * t).round(), (ag + bg * t).round(),
+      (ab + bb * t).round(), 1.0).toRgbaString();
 }
 
 /// Generate an interpolator using HSL color system converted to Hex string.
 Interpolator createHslColorInterpolator(Color a, Color b) {
   if (a == null || b == null) return (t) => b;
-  var ah = a.h,
-      as = a.s,
-      al = a.l,
-      bh = b.h - ah,
-      bs = b.s - as,
-      bl = b.l - al;
+  var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
 
-  return (t) => new Color.fromHsla((ah + bh * t).round(),
-      (as + bs * t).round(), (al + bl * t).round(), 1.0).toHslaString();
+  return (t) => new Color.fromHsla((ah + bh * t).round(), (as + bs * t).round(),
+      (al + bl * t).round(), 1.0).toHslaString();
 }
 
 /// Generates an interpolator to interpolate each element between lists
@@ -218,25 +209,21 @@
   var numRegExStr = r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?',
       numberRegEx = new RegExp(numRegExStr),
       translateRegEx =
-          new RegExp(r'translate\(' + '$numRegExStr,$numRegExStr' + r'\)'),
+      new RegExp(r'translate\(' + '$numRegExStr,$numRegExStr' + r'\)'),
       scaleRegEx =
-          new RegExp(r'scale\(' + numRegExStr + r',' + numRegExStr + r'\)'),
+      new RegExp(r'scale\(' + numRegExStr + r',' + numRegExStr + r'\)'),
       rotateRegEx = new RegExp(r'rotate\(' + numRegExStr + r'(deg)?\)'),
       skewRegEx = new RegExp(r'skewX\(' + numRegExStr + r'(deg)?\)'),
-
       translateA = translateRegEx.firstMatch(a),
       scaleA = scaleRegEx.firstMatch(a),
       rotateA = rotateRegEx.firstMatch(a),
       skewA = skewRegEx.firstMatch(a),
-
       translateB = translateRegEx.firstMatch(b),
       scaleB = scaleRegEx.firstMatch(b),
       rotateB = rotateRegEx.firstMatch(b),
       skewB = skewRegEx.firstMatch(b);
 
-  var numSetA = [],
-      numSetB = [],
-      tempStr, match;
+  var numSetA = [], numSetB = [], tempStr, match;
 
   // translate
   if (translateA != null) {
@@ -246,7 +233,7 @@
       numSetA.add(num.parse(m.group(0)));
     }
   } else {
-    numSetA.addAll(const[0, 0]);
+    numSetA.addAll(const [0, 0]);
   }
 
   if (translateB != null) {
@@ -256,7 +243,7 @@
       numSetB.add(num.parse(m.group(0)));
     }
   } else {
-    numSetB.addAll(const[0, 0]);
+    numSetB.addAll(const [0, 0]);
   }
 
   // scale
@@ -267,7 +254,7 @@
       numSetA.add(num.parse(m.group(0)));
     }
   } else {
-    numSetA.addAll(const[1, 1]);
+    numSetA.addAll(const [1, 1]);
   }
 
   if (scaleB != null) {
@@ -277,7 +264,7 @@
       numSetB.add(num.parse(m.group(0)));
     }
   } else {
-    numSetB.addAll(const[1, 1]);
+    numSetB.addAll(const [1, 1]);
   }
 
   // rotate
@@ -324,11 +311,10 @@
   }
 
   return (t) {
-    return
-        'translate(${createNumberInterpolator(numSetA[0], numSetB[0])(t)},'
-            '${createNumberInterpolator(numSetA[1], numSetB[1])(t)})'
+    return 'translate(${createNumberInterpolator(numSetA[0], numSetB[0])(t)},'
+        '${createNumberInterpolator(numSetA[1], numSetB[1])(t)})'
         'scale(${createNumberInterpolator(numSetA[2], numSetB[2])(t)},'
-            '${createNumberInterpolator(numSetA[3], numSetB[3])(t)})'
+        '${createNumberInterpolator(numSetA[3], numSetB[3])(t)})'
         'rotate(${createNumberInterpolator(numSetA[4], numSetB[4])(t)})'
         'skewX(${createNumberInterpolator(numSetA[5], numSetB[5])(t)})';
   };
@@ -340,12 +326,9 @@
   if (a == null || b == null) return (t) => b;
   assert(a.length == b.length && a.length == 3);
 
-  var sqrt2 = math.SQRT2,
-      param2 = 2,
-      param4 = 4;
+  var sqrt2 = math.SQRT2, param2 = 2, param4 = 4;
 
-  var ux0 = a[0], uy0 = a[1], w0 = a[2],
-      ux1 = b[0], uy1 = b[1], w1 = b[2];
+  var ux0 = a[0], uy0 = a[1], w0 = a[2], ux1 = b[0], uy1 = b[1], w1 = b[2];
 
   var dx = ux1 - ux0,
       dy = uy1 - uy0,
@@ -364,18 +347,10 @@
       // General case.
       var coshr0 = cosh(r0),
           u = w0 / (param2 * d1) * (coshr0 * tanh(sqrt2 * s + r0) - sinh(r0));
-      return [
-        ux0 + u * dx,
-        uy0 + u * dy,
-        w0 * coshr0 / cosh(sqrt2 * s + r0)
-      ];
+      return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(sqrt2 * s + r0)];
     }
     // Special case for u0 ~= u1.
-    return [
-      ux0 + t * dx,
-      uy0 + t * dy,
-      w0 * math.exp(sqrt2 * s)
-    ];
+    return [ux0 + t * dx, uy0 + t * dy, w0 * math.exp(sqrt2 * s)];
   };
 }
 
diff --git a/packages/charted/lib/core/scales.dart b/packages/charted/lib/core/scales.dart
index 4acd744..e4a9948 100644
--- a/packages/charted/lib/core/scales.dart
+++ b/packages/charted/lib/core/scales.dart
@@ -106,7 +106,7 @@
   void rangeRoundBands(Iterable range, [double padding, double outerPadding]);
 }
 
-class RoundingFunctions extends Pair<RoundFunction,RoundFunction> {
+class RoundingFunctions extends Pair<RoundFunction, RoundFunction> {
   RoundingFunctions(RoundFunction floor, RoundFunction ceil)
       : super(floor, ceil);
 
@@ -123,10 +123,9 @@
 /// Namespacing container for utilities used by scales.
 abstract class ScaleUtils {
   /// Utility to return extent of sorted [values].
-  static Extent extent(Iterable values) =>
-      values.first < values.last
-          ? new Extent(values.first, values.last)
-          : new Extent(values.last, values.first);
+  static Extent extent(Iterable values) => values.first < values.last
+      ? new Extent(values.first, values.last)
+      : new Extent(values.last, values.first);
 
   /// Extends [values] to round numbers based on the given pair of
   /// floor and ceil functions.  [functions] is a pair of rounding function
@@ -156,8 +155,8 @@
   /// @param range          The range of the scale.
   /// @param uninterpolator The uninterpolator for domain values.
   /// @param interpolator   The interpolator for range values.
-  static Function bilinearScale(List domain, List range,
-      Function uninterpolator, Function interpolator) {
+  static Function bilinearScale(
+      List domain, List range, Function uninterpolator, Function interpolator) {
     var u = uninterpolator(domain[0], domain[1]),
         i = interpolator(range[0], range[1]);
     return (x) => i(u(x));
@@ -170,12 +169,9 @@
   /// @param range          The range of the scale.
   /// @param uninterpolator The uninterpolator for domain values.
   /// @param interpolator   The interpolator for range values.
-  static Function polylinearScale(List domain, List range,
-      Function uninterpolator, Function interpolator) {
-    var u = [],
-        i = [],
-        j = 0,
-        k = math.min(domain.length, range.length) - 1;
+  static Function polylinearScale(
+      List domain, List range, Function uninterpolator, Function interpolator) {
+    var u = [], i = [], j = 0, k = math.min(domain.length, range.length) - 1;
 
     // Handle descending domains.
     if (domain[k] < domain[0]) {
diff --git a/packages/charted/lib/core/scales/linear_scale.dart b/packages/charted/lib/core/scales/linear_scale.dart
index a0de8fb..4c983dc 100644
--- a/packages/charted/lib/core/scales/linear_scale.dart
+++ b/packages/charted/lib/core/scales/linear_scale.dart
@@ -40,15 +40,15 @@
           _domain, ScaleUtils.niceStep(_linearTickRange().step));
     }
 
-    Function linear = math.min(_domain.length, _range.length) > 2 ?
-        ScaleUtils.polylinearScale : ScaleUtils.bilinearScale;
+    Function linear = math.min(_domain.length, _range.length) > 2
+        ? ScaleUtils.polylinearScale
+        : ScaleUtils.bilinearScale;
 
     Function uninterpolator = clamp ? uninterpolateClamp : uninterpolateNumber;
     InterpolatorGenerator interpolator =
         _rounded ? createRoundedNumberInterpolator : createNumberInterpolator;
 
-    _invert =
-        linear(_range, _domain, uninterpolator, createNumberInterpolator);
+    _invert = linear(_range, _domain, uninterpolator, createNumberInterpolator);
     _scale = linear(_domain, _range, uninterpolator, interpolator);
   }
 
@@ -135,19 +135,19 @@
     if (extent == null) {
       extent = ScaleUtils.extent(_domain);
     }
-    var span = extent.max - extent.min,
-        step =
-            math.pow(10, (math.log(span / _ticksCount) / math.LN10).floor()),
-        err = _ticksCount / span * step;
+    var span = extent.max - extent.min;
+    if (span == 0) {
+      span = 1.0; // [span / _ticksCount] should never be equal zero.
+    }
+    var step = math.pow(10, (math.log(span / _ticksCount) / math.LN10).floor());
+    var err = _ticksCount / span * step;
 
     // Filter ticks to get closer to the desired count.
     if (err <= .15) {
       step *= 10;
-    }
-    else if (err <= .35) {
+    } else if (err <= .35) {
       step *= 5;
-    }
-    else if (err <= .75) {
+    } else if (err <= .75) {
       step *= 2;
     }
 
diff --git a/packages/charted/lib/core/scales/log_scale.dart b/packages/charted/lib/core/scales/log_scale.dart
index 20fc3a4..ae9d5b0 100644
--- a/packages/charted/lib/core/scales/log_scale.dart
+++ b/packages/charted/lib/core/scales/log_scale.dart
@@ -21,9 +21,7 @@
   static const defaultBase = 10;
   static const defaultDomain = const [1, 10];
   static final negativeNumbersRoundFunctionsPair =
-      new RoundingFunctions(
-          (x) => -((-x).floor()),
-          (x) => -((-x).ceil()));
+      new RoundingFunctions((x) => -((-x).floor()), (x) => -((-x).ceil()));
 
   final LinearScale _linear;
 
@@ -43,8 +41,9 @@
         _nice = source._nice,
         _ticksCount = source._ticksCount;
 
-  num _log(x) => (_positive ?
-      math.log(x < 0 ? 0 : x) : -math.log(x > 0 ? 0 : -x)) / math.log(base);
+  num _log(x) =>
+      (_positive ? math.log(x < 0 ? 0 : x) : -math.log(x > 0 ? 0 : -x)) /
+          math.log(base);
 
   num _pow(x) => _positive ? math.pow(base, x) : -math.pow(base, -x);
 
diff --git a/packages/charted/lib/core/scales/ordinal_scale.dart b/packages/charted/lib/core/scales/ordinal_scale.dart
index 6c135a2..718966a 100644
--- a/packages/charted/lib/core/scales/ordinal_scale.dart
+++ b/packages/charted/lib/core/scales/ordinal_scale.dart
@@ -80,15 +80,15 @@
 
   @override
   void rangeBands(Iterable range,
-      [double padding = 0.0, double outerPadding]) =>
-          _setRangeBands(this, range, padding,
-              outerPadding == null ? padding : outerPadding);
+          [double padding = 0.0, double outerPadding]) =>
+      _setRangeBands(
+          this, range, padding, outerPadding == null ? padding : outerPadding);
 
   @override
   void rangeRoundBands(Iterable range,
-      [double padding = 0.0, double outerPadding]) =>
-          _setRangeRoundBands(this, range, padding,
-              outerPadding == null ? padding : outerPadding);
+          [double padding = 0.0, double outerPadding]) =>
+      _setRangeRoundBands(
+          this, range, padding, outerPadding == null ? padding : outerPadding);
 
   @override
   num get rangeBand => _rangeBand;
@@ -121,9 +121,9 @@
           stop = range.last,
           step = (stop - start) / (s.domain.length - 1 + padding);
 
-      s._range = s._steps(s.domain.length < 2
-          ? (start + stop) / 2
-          : start + step * padding / 2, step);
+      s._range = s._steps(
+          s.domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2,
+          step);
       s._rangeBand = 0;
       s._rangeExtent = new Extent(start, stop);
     };
@@ -132,8 +132,8 @@
     }
   }
 
-  static void _setRangeBands(_OrdinalScale scale,
-      Iterable range, double padding, double outerPadding) {
+  static void _setRangeBands(_OrdinalScale scale, Iterable range,
+      double padding, double outerPadding) {
     scale._reset = (_OrdinalScale s) {
       var start = range.first,
           stop = range.last,
@@ -143,13 +143,13 @@
       s._rangeBand = step * (1 - padding);
       s._rangeExtent = new Extent(start, stop);
     };
-    if (scale.domain.isNotEmpty){
+    if (scale.domain.isNotEmpty) {
       scale._reset(scale);
     }
   }
 
-  static void _setRangeRoundBands(_OrdinalScale scale,
-      Iterable range, double padding, double outerPadding) {
+  static void _setRangeRoundBands(_OrdinalScale scale, Iterable range,
+      double padding, double outerPadding) {
     scale._reset = (_OrdinalScale s) {
       var start = range.first,
           stop = range.last,
diff --git a/packages/charted/lib/core/scales/time_scale.dart b/packages/charted/lib/core/scales/time_scale.dart
index 8fba314..d1b439b 100644
--- a/packages/charted/lib/core/scales/time_scale.dart
+++ b/packages/charted/lib/core/scales/time_scale.dart
@@ -11,19 +11,19 @@
 /// TimeScale is a linear scale that operates on time.
 class TimeScale extends LinearScale {
   static const _scaleSteps = const [
-    1e3,    // 1-second
-    5e3,    // 5-second
-    15e3,   // 15-second
-    3e4,    // 30-second
-    6e4,    // 1-minute
-    3e5,    // 5-minute
-    9e5,    // 15-minute
-    18e5,   // 30-minute
-    36e5,   // 1-hour
-    108e5,  // 3-hour
-    216e5,  // 6-hour
-    432e5,  // 12-hour
-    864e5,  // 1-day
+    1e3, // 1-second
+    5e3, // 5-second
+    15e3, // 15-second
+    3e4, // 30-second
+    6e4, // 1-minute
+    3e5, // 5-minute
+    9e5, // 15-minute
+    18e5, // 30-minute
+    36e5, // 1-hour
+    108e5, // 3-hour
+    216e5, // 6-hour
+    432e5, // 12-hour
+    864e5, // 1-day
     1728e5, // 2-day
     6048e5, // 1-week
     2592e6, // 1-month
@@ -40,27 +40,27 @@
     [TimeInterval.minute, 5],
     [TimeInterval.minute, 15],
     [TimeInterval.minute, 30],
-    [TimeInterval.hour,   1],
-    [TimeInterval.hour,   3],
-    [TimeInterval.hour,   6],
-    [TimeInterval.hour,   12],
-    [TimeInterval.day,    1],
-    [TimeInterval.day,    2],
-    [TimeInterval.week,   1],
-    [TimeInterval.month,  1],
-    [TimeInterval.month,  3],
-    [TimeInterval.year,   1]
+    [TimeInterval.hour, 1],
+    [TimeInterval.hour, 3],
+    [TimeInterval.hour, 6],
+    [TimeInterval.hour, 12],
+    [TimeInterval.day, 1],
+    [TimeInterval.day, 2],
+    [TimeInterval.week, 1],
+    [TimeInterval.month, 1],
+    [TimeInterval.month, 3],
+    [TimeInterval.year, 1]
   ];
 
   static TimeFormatFunction _scaleLocalFormat = new TimeFormat().multi([
-      [".%L",   (DateTime d) => d.millisecond > 0],
-      [":%S",   (DateTime d) => d.second > 0],
-      ["%I:%M", (DateTime d) => d.minute > 0],
-      ["%I %p", (DateTime d) => d.hour > 0],
-      ["%a %d", (DateTime d) => (d.weekday % 7) > 0 && d.day != 1],
-      ["%b %d", (DateTime d) => d.day != 1],
-      ["%B",    (DateTime d) => d.month > 1],
-      ["%Y",    (d) => true]
+    [".%L", (DateTime d) => d.millisecond > 0],
+    [":%S", (DateTime d) => d.second > 0],
+    ["%I:%M", (DateTime d) => d.minute > 0],
+    ["%I %p", (DateTime d) => d.hour > 0],
+    ["%a %d", (DateTime d) => (d.weekday % 7) > 0 && d.day != 1],
+    ["%b %d", (DateTime d) => d.day != 1],
+    ["%B", (DateTime d) => d.month > 1],
+    ["%Y", (d) => true]
   ]);
 
   TimeScale();
@@ -72,8 +72,8 @@
 
   @override
   set domain(Iterable value) {
-    super.domain = value.map(
-        (d) => d is DateTime ? d.millisecondsSinceEpoch : d).toList();
+    super.domain =
+        value.map((d) => d is DateTime ? d.millisecondsSinceEpoch : d).toList();
   }
 
   @override
@@ -83,16 +83,19 @@
   TimeScale clone() => new TimeScale._clone(this);
 
   List _getTickMethod(Extent extent, int count) {
-    var target  = (extent.max - extent.min) / count,
+    var target = (extent.max - extent.min) / count,
         i = ScaleUtils.bisect(_scaleSteps, target);
 
     return i == _scaleSteps.length
-        ? [ TimeInterval.year, _linearTickRange(
-            new Extent(extent.min / 31536e6, extent.max / 31536e6)).step ]
+        ? [
+            TimeInterval.year,
+            _linearTickRange(
+                new Extent(extent.min / 31536e6, extent.max / 31536e6)).step
+          ]
         : i == 0
-            ? [ new ScaleMilliSeconds(), _linearTickRange(extent).step ]
-            : _scaleLocalMethods[
-                target / _scaleSteps[i - 1] < _scaleSteps[i] / target ? i - 1 : i];
+            ? [new ScaleMilliSeconds(), _linearTickRange(extent).step]
+            : _scaleLocalMethods[target / _scaleSteps[i - 1] <
+                _scaleSteps[i] / target ? i - 1 : i];
   }
 
   List niceInterval(int ticksCount, [int skip = 1]) {
@@ -107,30 +110,29 @@
 
     bool skipped(var date) {
       if (date is DateTime) date = date.millisecondsSinceEpoch;
-      return (interval as TimeInterval)
-          .range(date, date + 1, skip).length == 0;
+      return (interval as TimeInterval).range(date, date + 1, skip).length == 0;
     }
 
     if (skip > 1) {
-      domain = ScaleUtils.nice(domain, new RoundingFunctions(
-        (date) {
-          while (skipped(date = (interval as TimeInterval).floor(date))) {
-            date = new DateTime.fromMillisecondsSinceEpoch(
-                date.millisecondsSinceEpoch - 1);
-          }
-          return date.millisecondsSinceEpoch;
-        },
-        (date) {
-          while (skipped(date = (interval as TimeInterval).ceil(date))) {
-            date = new DateTime.fromMillisecondsSinceEpoch(
-                date.millisecondsSinceEpoch + 1);
-          }
-          return date.millisecondsSinceEpoch;
-        }
-      ));
+      domain = ScaleUtils.nice(
+          domain,
+          new RoundingFunctions((date) {
+            while (skipped(date = (interval as TimeInterval).floor(date))) {
+              date = new DateTime.fromMillisecondsSinceEpoch(
+                  date.millisecondsSinceEpoch - 1);
+            }
+            return date.millisecondsSinceEpoch;
+          }, (date) {
+            while (skipped(date = (interval as TimeInterval).ceil(date))) {
+              date = new DateTime.fromMillisecondsSinceEpoch(
+                  date.millisecondsSinceEpoch + 1);
+            }
+            return date.millisecondsSinceEpoch;
+          }));
     } else {
       domain = ScaleUtils.nice(
-          domain, new RoundingFunctions(
+          domain,
+          new RoundingFunctions(
               (date) => interval.floor(date).millisecondsSinceEpoch,
               (date) => interval.ceil(date).millisecondsSinceEpoch));
     }
@@ -163,9 +165,10 @@
 
 class ScaleMilliSeconds implements TimeInterval {
   DateTime _toDateTime(x) {
-    assert (x is int || x is DateTime);
+    assert(x is int || x is DateTime);
     return x is num ? new DateTime.fromMillisecondsSinceEpoch(x) : x;
   }
+
   DateTime floor(dynamic val) => _toDateTime(val);
   DateTime ceil(dynamic val) => _toDateTime(val);
   DateTime round(dynamic val) => _toDateTime(val);
@@ -179,7 +182,8 @@
   List range(var t0, var t1, int step) {
     int start = t0 is DateTime ? t0.millisecondsSinceEpoch : t0,
         stop = t1 is DateTime ? t1.millisecondsSinceEpoch : t1;
-    return new Range((start / step).ceil() * step, stop, step).map(
-        (d) => new DateTime.fromMillisecondsSinceEpoch(d)).toList();
+    return new Range((start / step).ceil() * step, stop, step)
+        .map((d) => new DateTime.fromMillisecondsSinceEpoch(d))
+        .toList();
   }
 }
diff --git a/packages/charted/lib/core/text_metrics.dart b/packages/charted/lib/core/text_metrics.dart
index 5933594..9fb7d06 100644
--- a/packages/charted/lib/core/text_metrics.dart
+++ b/packages/charted/lib/core/text_metrics.dart
@@ -57,17 +57,17 @@
   double getTextWidth(String text, {String fontStyle}) {
     assert(text.length <= MAX_STRING_LENGTH);
     setFontStyle(fontStyle);
-    return context.measureText(text).width;
+    return context.measureText(text).width.toDouble();
   }
 
   /// Gets length of the longest string in the given [strings].
   /// Optionally, uses [fontStyle] instead of using the default style.
   double getLongestTextWidth(Iterable<String> strings, {String fontStyle}) {
     setFontStyle(fontStyle);
-    double maxWidth = 0.0;
+    num maxWidth = 0.0;
     for (int i = 0; i < strings.length; ++i) {
       assert(strings.elementAt(i).length <= MAX_STRING_LENGTH);
-      double width = context.measureText(strings.elementAt(i)).width;
+      double width = context.measureText(strings.elementAt(i)).width.toDouble();
       if (width > maxWidth) {
         maxWidth = width;
       }
@@ -79,14 +79,16 @@
   /// Truncates given [text] to fit in [width]. Adds an ellipsis to the
   /// returned string, if it needed to be truncated.
   /// Optionally, uses [fontStyle] instead of using the default style.
-  String ellipsizeText(String text, double width, {String fontStyle}) {
+  String ellipsizeText(String text, num width, {String fontStyle}) {
     assert(text.length <= MAX_STRING_LENGTH);
     setFontStyle(fontStyle);
-    double computedWidth = context.measureText(text).width;
+    double computedWidth = context.measureText(text).width.toDouble();
     if (computedWidth > width) {
       var indices = graphemeBreakIndices(text);
       var position = 0,
-          min = 0, max = indices.length - 1, mid,
+          min = 0,
+          max = indices.length - 1,
+          mid,
           ellipsis = context.measureText('…').width;
       width = width - ellipsis;
       while (max >= min) {
@@ -108,6 +110,5 @@
   /// if it had to be truncated.
   /// Calling this method may force a layout on the document. For better
   /// performance, use [TextMetrics.ellipsizeText].
-  static ellipsizeTextElement() {
-  }
+  static ellipsizeTextElement() {}
 }
diff --git a/packages/charted/lib/core/text_metrics/segmentation.dart b/packages/charted/lib/core/text_metrics/segmentation.dart
index b1c6c31..058ac38 100644
--- a/packages/charted/lib/core/text_metrics/segmentation.dart
+++ b/packages/charted/lib/core/text_metrics/segmentation.dart
@@ -18,19 +18,151 @@
 // Code table based on:
 // http://www.unicode.org/Public/7.0.0/ucd/auxiliary/GraphemeBreakTest.html
 // GRAPHEME_BREAK_TABLE[prevType * TYPE_COUNT + curType] == 1 means break.
-const GRAPHEME_BREAK_TABLE = const[
-    1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
-    1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1,
-    1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
-    1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0
+const GRAPHEME_BREAK_TABLE = const [
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  0,
+  0,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0,
+  0,
+  1,
+  1,
+  1,
+  1,
+  1,
+  0
 ];
 
 /// Get type of a given char code.
@@ -41,13 +173,12 @@
   while (max >= min) {
     int mid = (max + min) ~/ 2;
     int idx = mid * 3;
-    if (CODE_POINT_BLOCKS[idx] <= rune && rune <= CODE_POINT_BLOCKS[idx+1]) {
-      return CODE_POINT_BLOCKS[idx+2]; // Return the found character type
+    if (CODE_POINT_BLOCKS[idx] <= rune && rune <= CODE_POINT_BLOCKS[idx + 1]) {
+      return CODE_POINT_BLOCKS[idx + 2]; // Return the found character type
     }
     if (CODE_POINT_BLOCKS[idx] > rune) {
       max = mid - 1;
-    }
-    else if (CODE_POINT_BLOCKS[idx+1] < rune) {
+    } else if (CODE_POINT_BLOCKS[idx + 1] < rune) {
       min = max + 1;
     }
   }
diff --git a/packages/charted/lib/core/text_metrics/segmentation_data.dart b/packages/charted/lib/core/text_metrics/segmentation_data.dart
index 3145759..66883c2 100644
--- a/packages/charted/lib/core/text_metrics/segmentation_data.dart
+++ b/packages/charted/lib/core/text_metrics/segmentation_data.dart
@@ -15,1189 +15,3557 @@
 
 /// Each line in the following list represents a code range.
 /// Start, End, Type.
-const CODE_POINT_BLOCKS = const[
-  0, 9, 3,
-  10, 10, 2,
-  11, 12, 3,
-  13, 13, 1,
-  14, 31, 3,
-  127, 159, 3,
-  173, 173, 3,
-  768, 879, 4,
-  1155, 1159, 4,
-  1160, 1161, 4,
-  1425, 1469, 4,
-  1471, 1471, 4,
-  1473, 1474, 4,
-  1476, 1477, 4,
-  1479, 1479, 4,
-  1536, 1541, 3,
-  1552, 1562, 4,
-  1564, 1564, 3,
-  1611, 1631, 4,
-  1648, 1648, 4,
-  1750, 1756, 4,
-  1757, 1757, 3,
-  1759, 1764, 4,
-  1767, 1768, 4,
-  1770, 1773, 4,
-  1807, 1807, 3,
-  1809, 1809, 4,
-  1840, 1866, 4,
-  1958, 1968, 4,
-  2027, 2035, 4,
-  2070, 2073, 4,
-  2075, 2083, 4,
-  2085, 2087, 4,
-  2089, 2093, 4,
-  2137, 2139, 4,
-  2276, 2306, 4,
-  2307, 2307, 5,
-  2362, 2362, 4,
-  2363, 2363, 5,
-  2364, 2364, 4,
-  2366, 2368, 5,
-  2369, 2376, 4,
-  2377, 2380, 5,
-  2381, 2381, 4,
-  2382, 2383, 5,
-  2385, 2391, 4,
-  2402, 2403, 4,
-  2433, 2433, 4,
-  2434, 2435, 5,
-  2492, 2492, 4,
-  2494, 2494, 4,
-  2495, 2496, 5,
-  2497, 2500, 4,
-  2503, 2504, 5,
-  2507, 2508, 5,
-  2509, 2509, 4,
-  2519, 2519, 4,
-  2530, 2531, 4,
-  2561, 2562, 4,
-  2563, 2563, 5,
-  2620, 2620, 4,
-  2622, 2624, 5,
-  2625, 2626, 4,
-  2631, 2632, 4,
-  2635, 2637, 4,
-  2641, 2641, 4,
-  2672, 2673, 4,
-  2677, 2677, 4,
-  2689, 2690, 4,
-  2691, 2691, 5,
-  2748, 2748, 4,
-  2750, 2752, 5,
-  2753, 2757, 4,
-  2759, 2760, 4,
-  2761, 2761, 5,
-  2763, 2764, 5,
-  2765, 2765, 4,
-  2786, 2787, 4,
-  2817, 2817, 4,
-  2818, 2819, 5,
-  2876, 2876, 4,
-  2878, 2878, 4,
-  2879, 2879, 4,
-  2880, 2880, 5,
-  2881, 2884, 4,
-  2887, 2888, 5,
-  2891, 2892, 5,
-  2893, 2893, 4,
-  2902, 2902, 4,
-  2903, 2903, 4,
-  2914, 2915, 4,
-  2946, 2946, 4,
-  3006, 3006, 4,
-  3007, 3007, 5,
-  3008, 3008, 4,
-  3009, 3010, 5,
-  3014, 3016, 5,
-  3018, 3020, 5,
-  3021, 3021, 4,
-  3031, 3031, 4,
-  3072, 3072, 4,
-  3073, 3075, 5,
-  3134, 3136, 4,
-  3137, 3140, 5,
-  3142, 3144, 4,
-  3146, 3149, 4,
-  3157, 3158, 4,
-  3170, 3171, 4,
-  3201, 3201, 4,
-  3202, 3203, 5,
-  3260, 3260, 4,
-  3262, 3262, 5,
-  3263, 3263, 4,
-  3264, 3265, 5,
-  3266, 3266, 4,
-  3267, 3268, 5,
-  3270, 3270, 4,
-  3271, 3272, 5,
-  3274, 3275, 5,
-  3276, 3277, 4,
-  3285, 3286, 4,
-  3298, 3299, 4,
-  3329, 3329, 4,
-  3330, 3331, 5,
-  3390, 3390, 4,
-  3391, 3392, 5,
-  3393, 3396, 4,
-  3398, 3400, 5,
-  3402, 3404, 5,
-  3405, 3405, 4,
-  3415, 3415, 4,
-  3426, 3427, 4,
-  3458, 3459, 5,
-  3530, 3530, 4,
-  3535, 3535, 4,
-  3536, 3537, 5,
-  3538, 3540, 4,
-  3542, 3542, 4,
-  3544, 3550, 5,
-  3551, 3551, 4,
-  3570, 3571, 5,
-  3633, 3633, 4,
-  3635, 3635, 5,
-  3636, 3642, 4,
-  3655, 3662, 4,
-  3761, 3761, 4,
-  3763, 3763, 5,
-  3764, 3769, 4,
-  3771, 3772, 4,
-  3784, 3789, 4,
-  3864, 3865, 4,
-  3893, 3893, 4,
-  3895, 3895, 4,
-  3897, 3897, 4,
-  3902, 3903, 5,
-  3953, 3966, 4,
-  3967, 3967, 5,
-  3968, 3972, 4,
-  3974, 3975, 4,
-  3981, 3991, 4,
-  3993, 4028, 4,
-  4038, 4038, 4,
-  4127, 4127, 4,
-  4141, 4144, 4,
-  4142, 4142, 4,
-  4145, 4145, 5,
-  4146, 4151, 4,
-  4153, 4154, 4,
-  4155, 4156, 5,
-  4157, 4158, 4,
-  4182, 4183, 5,
-  4184, 4185, 4,
-  4190, 4192, 4,
-  4209, 4212, 4,
-  4226, 4226, 4,
-  4228, 4228, 5,
-  4229, 4230, 4,
-  4237, 4237, 4,
-  4253, 4253, 4,
-  4259, 4259, 4,
-  4352, 4352, 5,
-  4352, 4447, 6,
-  4352, 4352, 4,
-  4352, 4352, 5,
-  4360, 4360, 5,
-  4363, 4363, 3,
-  4370, 4370, 5,
-  4375, 4375, 4,
-  4376, 4376, 5,
-  4387, 4387, 4,
-  4387, 4387, 5,
-  4397, 4397, 4,
-  4400, 4400, 4,
-  4403, 4403, 5,
-  4403, 4403, 4,
-  4403, 4403, 4,
-  4404, 4404, 4,
-  4405, 4405, 4,
-  4427, 4427, 5,
-  4427, 4427, 4,
-  4427, 4427, 5,
-  4427, 4427, 4,
-  4427, 4427, 4,
-  4428, 4428, 5,
-  4442, 4442, 4,
-  4443, 4443, 5,
-  4448, 4519, 7,
-  4451, 4451, 5,
-  4451, 4451, 4,
-  4458, 4458, 4,
-  4458, 4458, 5,
-  4458, 4458, 4,
-  4459, 4459, 4,
-  4459, 4459, 5,
-  4520, 4607, 8,
-  4957, 4959, 4,
-  5906, 5908, 4,
-  5938, 5940, 4,
-  5970, 5971, 4,
-  6002, 6003, 4,
-  6068, 6069, 4,
-  6070, 6070, 5,
-  6071, 6077, 4,
-  6078, 6085, 5,
-  6086, 6086, 4,
-  6087, 6088, 5,
-  6089, 6099, 4,
-  6109, 6109, 4,
-  6155, 6157, 4,
-  6158, 6158, 3,
-  6313, 6313, 4,
-  6432, 6434, 4,
-  6435, 6438, 5,
-  6439, 6440, 4,
-  6441, 6443, 5,
-  6448, 6449, 5,
-  6450, 6450, 4,
-  6451, 6456, 5,
-  6457, 6459, 4,
-  6581, 6583, 5,
-  6586, 6586, 5,
-  6679, 6680, 4,
-  6681, 6682, 5,
-  6683, 6683, 4,
-  6741, 6741, 5,
-  6742, 6742, 4,
-  6743, 6743, 5,
-  6744, 6750, 4,
-  6752, 6752, 4,
-  6754, 6754, 4,
-  6757, 6764, 4,
-  6765, 6770, 5,
-  6771, 6780, 4,
-  6783, 6783, 4,
-  6832, 6845, 4,
-  6846, 6846, 4,
-  6912, 6915, 4,
-  6916, 6916, 5,
-  6964, 6964, 4,
-  6965, 6965, 5,
-  6966, 6970, 4,
-  6971, 6971, 5,
-  6972, 6972, 4,
-  6973, 6977, 5,
-  6978, 6978, 4,
-  6979, 6980, 5,
-  7019, 7027, 4,
-  7040, 7041, 4,
-  7042, 7042, 5,
-  7073, 7073, 5,
-  7074, 7077, 4,
-  7078, 7079, 5,
-  7080, 7081, 4,
-  7082, 7082, 5,
-  7083, 7085, 4,
-  7142, 7142, 4,
-  7143, 7143, 5,
-  7144, 7145, 4,
-  7146, 7148, 5,
-  7149, 7149, 4,
-  7150, 7150, 5,
-  7151, 7153, 4,
-  7154, 7155, 5,
-  7204, 7211, 5,
-  7212, 7219, 4,
-  7220, 7221, 5,
-  7222, 7223, 4,
-  7376, 7378, 4,
-  7380, 7392, 4,
-  7393, 7393, 5,
-  7394, 7400, 4,
-  7405, 7405, 4,
-  7410, 7411, 5,
-  7412, 7412, 4,
-  7416, 7417, 4,
-  7446, 7446, 4,
-  7446, 7446, 5,
-  7446, 7446, 5,
-  7616, 7669, 4,
-  7676, 7679, 4,
-  8203, 8203, 3,
-  8204, 8205, 4,
-  8206, 8207, 3,
-  8232, 8232, 3,
-  8233, 8233, 3,
-  8234, 8238, 3,
-  8288, 8292, 3,
-  8293, 8293, 3,
-  8294, 8303, 3,
-  8400, 8412, 4,
-  8413, 8416, 4,
-  8417, 8417, 4,
-  8418, 8420, 4,
-  8421, 8432, 4,
-  11503, 11505, 4,
-  11647, 11647, 4,
-  11744, 11775, 4,
-  12330, 12333, 4,
-  12334, 12335, 4,
-  12441, 12442, 4,
-  42607, 42607, 4,
-  42608, 42610, 4,
-  42612, 42621, 4,
-  42655, 42655, 4,
-  42736, 42737, 4,
-  43010, 43010, 4,
-  43014, 43014, 4,
-  43019, 43019, 4,
-  43043, 43044, 5,
-  43045, 43046, 4,
-  43047, 43047, 5,
-  43136, 43137, 5,
-  43188, 43203, 5,
-  43204, 43204, 4,
-  43232, 43249, 4,
-  43302, 43309, 4,
-  43335, 43345, 4,
-  43346, 43347, 5,
-  43360, 43388, 6,
-  43392, 43394, 4,
-  43395, 43395, 5,
-  43443, 43443, 4,
-  43444, 43445, 5,
-  43446, 43449, 4,
-  43450, 43451, 5,
-  43452, 43452, 4,
-  43453, 43456, 5,
-  43493, 43493, 4,
-  43561, 43566, 4,
-  43567, 43568, 5,
-  43569, 43570, 4,
-  43571, 43572, 5,
-  43573, 43574, 4,
-  43587, 43587, 4,
-  43596, 43596, 4,
-  43597, 43597, 5,
-  43644, 43644, 4,
-  43696, 43696, 4,
-  43698, 43700, 4,
-  43703, 43704, 4,
-  43710, 43711, 4,
-  43713, 43713, 4,
-  43755, 43755, 5,
-  43756, 43757, 4,
-  43758, 43759, 5,
-  43765, 43765, 5,
-  43766, 43766, 4,
-  44003, 44004, 5,
-  44005, 44005, 4,
-  44006, 44007, 5,
-  44008, 44008, 4,
-  44009, 44010, 5,
-  44012, 44012, 5,
-  44013, 44013, 4,
-  44032, 44032, 9,
-  44033, 44059, 10,
-  44060, 44060, 9,
-  44061, 44087, 10,
-  44088, 44088, 9,
-  44089, 44115, 10,
-  44116, 44116, 9,
-  44117, 44143, 10,
-  44144, 44144, 9,
-  44145, 44171, 10,
-  44172, 44172, 9,
-  44173, 44199, 10,
-  44200, 44200, 9,
-  44201, 44227, 10,
-  44228, 44228, 9,
-  44229, 44255, 10,
-  44256, 44256, 9,
-  44257, 44283, 10,
-  44284, 44284, 9,
-  44285, 44311, 10,
-  44312, 44312, 9,
-  44313, 44339, 10,
-  44340, 44340, 9,
-  44341, 44367, 10,
-  44368, 44368, 9,
-  44369, 44395, 10,
-  44396, 44396, 9,
-  44397, 44423, 10,
-  44424, 44424, 9,
-  44425, 44451, 10,
-  44452, 44452, 9,
-  44453, 44479, 10,
-  44480, 44480, 9,
-  44481, 44507, 10,
-  44508, 44508, 9,
-  44509, 44535, 10,
-  44536, 44536, 9,
-  44537, 44563, 10,
-  44564, 44564, 9,
-  44565, 44591, 10,
-  44592, 44592, 9,
-  44593, 44619, 10,
-  44620, 44620, 9,
-  44621, 44647, 10,
-  44648, 44648, 9,
-  44649, 44675, 10,
-  44676, 44676, 9,
-  44677, 44703, 10,
-  44704, 44704, 9,
-  44705, 44731, 10,
-  44732, 44732, 9,
-  44733, 44759, 10,
-  44760, 44760, 9,
-  44761, 44787, 10,
-  44788, 44788, 9,
-  44789, 44815, 10,
-  44816, 44816, 9,
-  44817, 44843, 10,
-  44844, 44844, 9,
-  44845, 44871, 10,
-  44872, 44872, 9,
-  44873, 44899, 10,
-  44900, 44900, 9,
-  44901, 44927, 10,
-  44928, 44928, 9,
-  44929, 44955, 10,
-  44956, 44956, 9,
-  44957, 44983, 10,
-  44984, 44984, 9,
-  44985, 45011, 10,
-  45012, 45012, 9,
-  45013, 45039, 10,
-  45040, 45040, 9,
-  45041, 45067, 10,
-  45068, 45068, 9,
-  45069, 45095, 10,
-  45096, 45096, 9,
-  45097, 45123, 10,
-  45124, 45124, 9,
-  45125, 45151, 10,
-  45152, 45152, 9,
-  45153, 45179, 10,
-  45180, 45180, 9,
-  45181, 45207, 10,
-  45208, 45208, 9,
-  45209, 45235, 10,
-  45236, 45236, 9,
-  45237, 45263, 10,
-  45264, 45264, 9,
-  45265, 45291, 10,
-  45292, 45292, 9,
-  45293, 45319, 10,
-  45320, 45320, 9,
-  45321, 45347, 10,
-  45348, 45348, 9,
-  45349, 45375, 10,
-  45376, 45376, 9,
-  45377, 45403, 10,
-  45404, 45404, 9,
-  45405, 45431, 10,
-  45432, 45432, 9,
-  45433, 45459, 10,
-  45460, 45460, 9,
-  45461, 45487, 10,
-  45488, 45488, 9,
-  45489, 45515, 10,
-  45516, 45516, 9,
-  45517, 45543, 10,
-  45544, 45544, 9,
-  45545, 45571, 10,
-  45572, 45572, 9,
-  45573, 45599, 10,
-  45600, 45600, 9,
-  45601, 45627, 10,
-  45628, 45628, 9,
-  45629, 45655, 10,
-  45656, 45656, 9,
-  45657, 45683, 10,
-  45684, 45684, 9,
-  45685, 45711, 10,
-  45712, 45712, 9,
-  45713, 45739, 10,
-  45740, 45740, 9,
-  45741, 45767, 10,
-  45768, 45768, 9,
-  45769, 45795, 10,
-  45796, 45796, 9,
-  45797, 45823, 10,
-  45824, 45824, 9,
-  45825, 45851, 10,
-  45852, 45852, 9,
-  45853, 45879, 10,
-  45880, 45880, 9,
-  45881, 45907, 10,
-  45908, 45908, 9,
-  45909, 45935, 10,
-  45936, 45936, 9,
-  45937, 45963, 10,
-  45964, 45964, 9,
-  45965, 45991, 10,
-  45992, 45992, 9,
-  45993, 46019, 10,
-  46020, 46020, 9,
-  46021, 46047, 10,
-  46048, 46048, 9,
-  46049, 46075, 10,
-  46076, 46076, 9,
-  46077, 46103, 10,
-  46104, 46104, 9,
-  46105, 46131, 10,
-  46132, 46132, 9,
-  46133, 46159, 10,
-  46160, 46160, 9,
-  46161, 46187, 10,
-  46188, 46188, 9,
-  46189, 46215, 10,
-  46216, 46216, 9,
-  46217, 46243, 10,
-  46244, 46244, 9,
-  46245, 46271, 10,
-  46272, 46272, 9,
-  46273, 46299, 10,
-  46300, 46300, 9,
-  46301, 46327, 10,
-  46328, 46328, 9,
-  46329, 46355, 10,
-  46356, 46356, 9,
-  46357, 46383, 10,
-  46384, 46384, 9,
-  46385, 46411, 10,
-  46412, 46412, 9,
-  46413, 46439, 10,
-  46440, 46440, 9,
-  46441, 46467, 10,
-  46468, 46468, 9,
-  46469, 46495, 10,
-  46496, 46496, 9,
-  46497, 46523, 10,
-  46524, 46524, 9,
-  46525, 46551, 10,
-  46552, 46552, 9,
-  46553, 46579, 10,
-  46580, 46580, 9,
-  46581, 46607, 10,
-  46608, 46608, 9,
-  46609, 46635, 10,
-  46636, 46636, 9,
-  46637, 46663, 10,
-  46664, 46664, 9,
-  46665, 46691, 10,
-  46692, 46692, 9,
-  46693, 46719, 10,
-  46720, 46720, 9,
-  46721, 46747, 10,
-  46748, 46748, 9,
-  46749, 46775, 10,
-  46776, 46776, 9,
-  46777, 46803, 10,
-  46804, 46804, 9,
-  46805, 46831, 10,
-  46832, 46832, 9,
-  46833, 46859, 10,
-  46860, 46860, 9,
-  46861, 46887, 10,
-  46888, 46888, 9,
-  46889, 46915, 10,
-  46916, 46916, 9,
-  46917, 46943, 10,
-  46944, 46944, 9,
-  46945, 46971, 10,
-  46972, 46972, 9,
-  46973, 46999, 10,
-  47000, 47000, 9,
-  47001, 47027, 10,
-  47028, 47028, 9,
-  47029, 47055, 10,
-  47056, 47056, 9,
-  47057, 47083, 10,
-  47084, 47084, 9,
-  47085, 47111, 10,
-  47112, 47112, 9,
-  47113, 47139, 10,
-  47140, 47140, 9,
-  47141, 47167, 10,
-  47168, 47168, 9,
-  47169, 47195, 10,
-  47196, 47196, 9,
-  47197, 47223, 10,
-  47224, 47224, 9,
-  47225, 47251, 10,
-  47252, 47252, 9,
-  47253, 47279, 10,
-  47280, 47280, 9,
-  47281, 47307, 10,
-  47308, 47308, 9,
-  47309, 47335, 10,
-  47336, 47336, 9,
-  47337, 47363, 10,
-  47364, 47364, 9,
-  47365, 47391, 10,
-  47392, 47392, 9,
-  47393, 47419, 10,
-  47420, 47420, 9,
-  47421, 47447, 10,
-  47448, 47448, 9,
-  47449, 47475, 10,
-  47476, 47476, 9,
-  47477, 47503, 10,
-  47504, 47504, 9,
-  47505, 47531, 10,
-  47532, 47532, 9,
-  47533, 47559, 10,
-  47560, 47560, 9,
-  47561, 47587, 10,
-  47588, 47588, 9,
-  47589, 47615, 10,
-  47616, 47616, 9,
-  47617, 47643, 10,
-  47644, 47644, 9,
-  47645, 47671, 10,
-  47672, 47672, 9,
-  47673, 47699, 10,
-  47700, 47700, 9,
-  47701, 47727, 10,
-  47728, 47728, 9,
-  47729, 47755, 10,
-  47756, 47756, 9,
-  47757, 47783, 10,
-  47784, 47784, 9,
-  47785, 47811, 10,
-  47812, 47812, 9,
-  47813, 47839, 10,
-  47840, 47840, 9,
-  47841, 47867, 10,
-  47868, 47868, 9,
-  47869, 47895, 10,
-  47896, 47896, 9,
-  47897, 47923, 10,
-  47924, 47924, 9,
-  47925, 47951, 10,
-  47952, 47952, 9,
-  47953, 47979, 10,
-  47980, 47980, 9,
-  47981, 48007, 10,
-  48008, 48008, 9,
-  48009, 48035, 10,
-  48036, 48036, 9,
-  48037, 48063, 10,
-  48064, 48064, 9,
-  48065, 48091, 10,
-  48092, 48092, 9,
-  48093, 48119, 10,
-  48120, 48120, 9,
-  48121, 48147, 10,
-  48148, 48148, 9,
-  48149, 48175, 10,
-  48176, 48176, 9,
-  48177, 48203, 10,
-  48204, 48204, 9,
-  48205, 48231, 10,
-  48232, 48232, 9,
-  48233, 48259, 10,
-  48260, 48260, 9,
-  48261, 48287, 10,
-  48288, 48288, 9,
-  48289, 48315, 10,
-  48316, 48316, 9,
-  48317, 48343, 10,
-  48344, 48344, 9,
-  48345, 48371, 10,
-  48372, 48372, 9,
-  48373, 48399, 10,
-  48400, 48400, 9,
-  48401, 48427, 10,
-  48428, 48428, 9,
-  48429, 48455, 10,
-  48456, 48456, 9,
-  48457, 48483, 10,
-  48484, 48484, 9,
-  48485, 48511, 10,
-  48512, 48512, 9,
-  48513, 48539, 10,
-  48540, 48540, 9,
-  48541, 48567, 10,
-  48568, 48568, 9,
-  48569, 48595, 10,
-  48596, 48596, 9,
-  48597, 48623, 10,
-  48624, 48624, 9,
-  48625, 48651, 10,
-  48652, 48652, 9,
-  48653, 48679, 10,
-  48680, 48680, 9,
-  48681, 48707, 10,
-  48708, 48708, 9,
-  48709, 48735, 10,
-  48736, 48736, 9,
-  48737, 48763, 10,
-  48764, 48764, 9,
-  48765, 48791, 10,
-  48792, 48792, 9,
-  48793, 48819, 10,
-  48820, 48820, 9,
-  48821, 48847, 10,
-  48848, 48848, 9,
-  48849, 48875, 10,
-  48876, 48876, 9,
-  48877, 48903, 10,
-  48904, 48904, 9,
-  48905, 48931, 10,
-  48932, 48932, 9,
-  48933, 48959, 10,
-  48960, 48960, 9,
-  48961, 48987, 10,
-  48988, 48988, 9,
-  48989, 49015, 10,
-  49016, 49016, 9,
-  49017, 49043, 10,
-  49044, 49044, 9,
-  49045, 49071, 10,
-  49072, 49072, 9,
-  49073, 49099, 10,
-  49100, 49100, 9,
-  49101, 49127, 10,
-  49128, 49128, 9,
-  49129, 49155, 10,
-  49156, 49156, 9,
-  49157, 49183, 10,
-  49184, 49184, 9,
-  49185, 49211, 10,
-  49212, 49212, 9,
-  49213, 49239, 10,
-  49240, 49240, 9,
-  49241, 49267, 10,
-  49268, 49268, 9,
-  49269, 49295, 10,
-  49296, 49296, 9,
-  49297, 49323, 10,
-  49324, 49324, 9,
-  49325, 49351, 10,
-  49352, 49352, 9,
-  49353, 49379, 10,
-  49380, 49380, 9,
-  49381, 49407, 10,
-  49408, 49408, 9,
-  49409, 49435, 10,
-  49436, 49436, 9,
-  49437, 49463, 10,
-  49464, 49464, 9,
-  49465, 49491, 10,
-  49492, 49492, 9,
-  49493, 49519, 10,
-  49520, 49520, 9,
-  49521, 49547, 10,
-  49548, 49548, 9,
-  49549, 49575, 10,
-  49576, 49576, 9,
-  49577, 49603, 10,
-  49604, 49604, 9,
-  49605, 49631, 10,
-  49632, 49632, 9,
-  49633, 49659, 10,
-  49660, 49660, 9,
-  49661, 49687, 10,
-  49688, 49688, 9,
-  49689, 49715, 10,
-  49716, 49716, 9,
-  49717, 49743, 10,
-  49744, 49744, 9,
-  49745, 49771, 10,
-  49772, 49772, 9,
-  49773, 49799, 10,
-  49800, 49800, 9,
-  49801, 49827, 10,
-  49828, 49828, 9,
-  49829, 49855, 10,
-  49856, 49856, 9,
-  49857, 49883, 10,
-  49884, 49884, 9,
-  49885, 49911, 10,
-  49912, 49912, 9,
-  49913, 49939, 10,
-  49940, 49940, 9,
-  49941, 49967, 10,
-  49968, 49968, 9,
-  49969, 49995, 10,
-  49996, 49996, 9,
-  49997, 50023, 10,
-  50024, 50024, 9,
-  50025, 50051, 10,
-  50052, 50052, 9,
-  50053, 50079, 10,
-  50080, 50080, 9,
-  50081, 50107, 10,
-  50108, 50108, 9,
-  50109, 50135, 10,
-  50136, 50136, 9,
-  50137, 50163, 10,
-  50164, 50164, 9,
-  50165, 50191, 10,
-  50192, 50192, 9,
-  50193, 50219, 10,
-  50220, 50220, 9,
-  50221, 50247, 10,
-  50248, 50248, 9,
-  50249, 50275, 10,
-  50276, 50276, 9,
-  50277, 50303, 10,
-  50304, 50304, 9,
-  50305, 50331, 10,
-  50332, 50332, 9,
-  50333, 50359, 10,
-  50360, 50360, 9,
-  50361, 50387, 10,
-  50388, 50388, 9,
-  50389, 50415, 10,
-  50416, 50416, 9,
-  50417, 50443, 10,
-  50444, 50444, 9,
-  50445, 50471, 10,
-  50472, 50472, 9,
-  50473, 50499, 10,
-  50500, 50500, 9,
-  50501, 50527, 10,
-  50528, 50528, 9,
-  50529, 50555, 10,
-  50556, 50556, 9,
-  50557, 50583, 10,
-  50584, 50584, 9,
-  50585, 50611, 10,
-  50612, 50612, 9,
-  50613, 50639, 10,
-  50640, 50640, 9,
-  50641, 50667, 10,
-  50668, 50668, 9,
-  50669, 50695, 10,
-  50696, 50696, 9,
-  50697, 50723, 10,
-  50724, 50724, 9,
-  50725, 50751, 10,
-  50752, 50752, 9,
-  50753, 50779, 10,
-  50780, 50780, 9,
-  50781, 50807, 10,
-  50808, 50808, 9,
-  50809, 50835, 10,
-  50836, 50836, 9,
-  50837, 50863, 10,
-  50864, 50864, 9,
-  50865, 50891, 10,
-  50892, 50892, 9,
-  50893, 50919, 10,
-  50920, 50920, 9,
-  50921, 50947, 10,
-  50948, 50948, 9,
-  50949, 50975, 10,
-  50976, 50976, 9,
-  50977, 51003, 10,
-  51004, 51004, 9,
-  51005, 51031, 10,
-  51032, 51032, 9,
-  51033, 51059, 10,
-  51060, 51060, 9,
-  51061, 51087, 10,
-  51088, 51088, 9,
-  51089, 51115, 10,
-  51116, 51116, 9,
-  51117, 51143, 10,
-  51144, 51144, 9,
-  51145, 51171, 10,
-  51172, 51172, 9,
-  51173, 51199, 10,
-  51200, 51200, 9,
-  51201, 51227, 10,
-  51228, 51228, 9,
-  51229, 51255, 10,
-  51256, 51256, 9,
-  51257, 51283, 10,
-  51284, 51284, 9,
-  51285, 51311, 10,
-  51312, 51312, 9,
-  51313, 51339, 10,
-  51340, 51340, 9,
-  51341, 51367, 10,
-  51368, 51368, 9,
-  51369, 51395, 10,
-  51396, 51396, 9,
-  51397, 51423, 10,
-  51424, 51424, 9,
-  51425, 51451, 10,
-  51452, 51452, 9,
-  51453, 51479, 10,
-  51480, 51480, 9,
-  51481, 51507, 10,
-  51508, 51508, 9,
-  51509, 51535, 10,
-  51536, 51536, 9,
-  51537, 51563, 10,
-  51564, 51564, 9,
-  51565, 51591, 10,
-  51592, 51592, 9,
-  51593, 51619, 10,
-  51620, 51620, 9,
-  51621, 51647, 10,
-  51648, 51648, 9,
-  51649, 51675, 10,
-  51676, 51676, 9,
-  51677, 51703, 10,
-  51704, 51704, 9,
-  51705, 51731, 10,
-  51732, 51732, 9,
-  51733, 51759, 10,
-  51760, 51760, 9,
-  51761, 51787, 10,
-  51788, 51788, 9,
-  51789, 51815, 10,
-  51816, 51816, 9,
-  51817, 51843, 10,
-  51844, 51844, 9,
-  51845, 51871, 10,
-  51872, 51872, 9,
-  51873, 51899, 10,
-  51900, 51900, 9,
-  51901, 51927, 10,
-  51928, 51928, 9,
-  51929, 51955, 10,
-  51956, 51956, 9,
-  51957, 51983, 10,
-  51984, 51984, 9,
-  51985, 52011, 10,
-  52012, 52012, 9,
-  52013, 52039, 10,
-  52040, 52040, 9,
-  52041, 52067, 10,
-  52068, 52068, 9,
-  52069, 52095, 10,
-  52096, 52096, 9,
-  52097, 52123, 10,
-  52124, 52124, 9,
-  52125, 52151, 10,
-  52152, 52152, 9,
-  52153, 52179, 10,
-  52180, 52180, 9,
-  52181, 52207, 10,
-  52208, 52208, 9,
-  52209, 52235, 10,
-  52236, 52236, 9,
-  52237, 52263, 10,
-  52264, 52264, 9,
-  52265, 52291, 10,
-  52292, 52292, 9,
-  52293, 52319, 10,
-  52320, 52320, 9,
-  52321, 52347, 10,
-  52348, 52348, 9,
-  52349, 52375, 10,
-  52376, 52376, 9,
-  52377, 52403, 10,
-  52404, 52404, 9,
-  52405, 52431, 10,
-  52432, 52432, 9,
-  52433, 52459, 10,
-  52460, 52460, 9,
-  52461, 52487, 10,
-  52488, 52488, 9,
-  52489, 52515, 10,
-  52516, 52516, 9,
-  52517, 52543, 10,
-  52544, 52544, 9,
-  52545, 52571, 10,
-  52572, 52572, 9,
-  52573, 52599, 10,
-  52600, 52600, 9,
-  52601, 52627, 10,
-  52628, 52628, 9,
-  52629, 52655, 10,
-  52656, 52656, 9,
-  52657, 52683, 10,
-  52684, 52684, 9,
-  52685, 52711, 10,
-  52712, 52712, 9,
-  52713, 52739, 10,
-  52740, 52740, 9,
-  52741, 52767, 10,
-  52768, 52768, 9,
-  52769, 52795, 10,
-  52796, 52796, 9,
-  52797, 52823, 10,
-  52824, 52824, 9,
-  52825, 52851, 10,
-  52852, 52852, 9,
-  52853, 52879, 10,
-  52880, 52880, 9,
-  52881, 52907, 10,
-  52908, 52908, 9,
-  52909, 52935, 10,
-  52936, 52936, 9,
-  52937, 52963, 10,
-  52964, 52964, 9,
-  52965, 52991, 10,
-  52992, 52992, 9,
-  52993, 53019, 10,
-  53020, 53020, 9,
-  53021, 53047, 10,
-  53048, 53048, 9,
-  53049, 53075, 10,
-  53076, 53076, 9,
-  53077, 53103, 10,
-  53104, 53104, 9,
-  53105, 53131, 10,
-  53132, 53132, 9,
-  53133, 53159, 10,
-  53160, 53160, 9,
-  53161, 53187, 10,
-  53188, 53188, 9,
-  53189, 53215, 10,
-  53216, 53216, 9,
-  53217, 53243, 10,
-  53244, 53244, 9,
-  53245, 53271, 10,
-  53272, 53272, 9,
-  53273, 53299, 10,
-  53300, 53300, 9,
-  53301, 53327, 10,
-  53328, 53328, 9,
-  53329, 53355, 10,
-  53356, 53356, 9,
-  53357, 53383, 10,
-  53384, 53384, 9,
-  53385, 53411, 10,
-  53412, 53412, 9,
-  53413, 53439, 10,
-  53440, 53440, 9,
-  53441, 53467, 10,
-  53468, 53468, 9,
-  53469, 53495, 10,
-  53496, 53496, 9,
-  53497, 53523, 10,
-  53524, 53524, 9,
-  53525, 53551, 10,
-  53552, 53552, 9,
-  53553, 53579, 10,
-  53580, 53580, 9,
-  53581, 53607, 10,
-  53608, 53608, 9,
-  53609, 53635, 10,
-  53636, 53636, 9,
-  53637, 53663, 10,
-  53664, 53664, 9,
-  53665, 53691, 10,
-  53692, 53692, 9,
-  53693, 53719, 10,
-  53720, 53720, 9,
-  53721, 53747, 10,
-  53748, 53748, 9,
-  53749, 53775, 10,
-  53776, 53776, 9,
-  53777, 53803, 10,
-  53804, 53804, 9,
-  53805, 53831, 10,
-  53832, 53832, 9,
-  53833, 53859, 10,
-  53860, 53860, 9,
-  53861, 53887, 10,
-  53888, 53888, 9,
-  53889, 53915, 10,
-  53916, 53916, 9,
-  53917, 53943, 10,
-  53944, 53944, 9,
-  53945, 53971, 10,
-  53972, 53972, 9,
-  53973, 53999, 10,
-  54000, 54000, 9,
-  54001, 54027, 10,
-  54028, 54028, 9,
-  54029, 54055, 10,
-  54056, 54056, 9,
-  54057, 54083, 10,
-  54084, 54084, 9,
-  54085, 54111, 10,
-  54112, 54112, 9,
-  54113, 54139, 10,
-  54140, 54140, 9,
-  54141, 54167, 10,
-  54168, 54168, 9,
-  54169, 54195, 10,
-  54196, 54196, 9,
-  54197, 54223, 10,
-  54224, 54224, 9,
-  54225, 54251, 10,
-  54252, 54252, 9,
-  54253, 54279, 10,
-  54280, 54280, 9,
-  54281, 54307, 10,
-  54308, 54308, 9,
-  54309, 54335, 10,
-  54336, 54336, 9,
-  54337, 54363, 10,
-  54364, 54364, 9,
-  54365, 54391, 10,
-  54392, 54392, 9,
-  54393, 54419, 10,
-  54420, 54420, 9,
-  54421, 54447, 10,
-  54448, 54448, 9,
-  54449, 54475, 10,
-  54476, 54476, 9,
-  54477, 54503, 10,
-  54504, 54504, 9,
-  54505, 54531, 10,
-  54532, 54532, 9,
-  54533, 54559, 10,
-  54560, 54560, 9,
-  54561, 54587, 10,
-  54588, 54588, 9,
-  54589, 54615, 10,
-  54616, 54616, 9,
-  54617, 54643, 10,
-  54644, 54644, 9,
-  54645, 54671, 10,
-  54672, 54672, 9,
-  54673, 54699, 10,
-  54700, 54700, 9,
-  54701, 54727, 10,
-  54728, 54728, 9,
-  54729, 54755, 10,
-  54756, 54756, 9,
-  54757, 54783, 10,
-  54784, 54784, 9,
-  54785, 54811, 10,
-  54812, 54812, 9,
-  54813, 54839, 10,
-  54840, 54840, 9,
-  54841, 54867, 10,
-  54868, 54868, 9,
-  54869, 54895, 10,
-  54896, 54896, 9,
-  54897, 54923, 10,
-  54924, 54924, 9,
-  54925, 54951, 10,
-  54952, 54952, 9,
-  54953, 54979, 10,
-  54980, 54980, 9,
-  54981, 55007, 10,
-  55008, 55008, 9,
-  55009, 55035, 10,
-  55036, 55036, 9,
-  55037, 55063, 10,
-  55064, 55064, 9,
-  55065, 55091, 10,
-  55092, 55092, 9,
-  55093, 55119, 10,
-  55120, 55120, 9,
-  55121, 55147, 10,
-  55148, 55148, 9,
-  55149, 55175, 10,
-  55176, 55176, 9,
-  55177, 55203, 10,
-  55216, 55238, 7,
-  55243, 55291, 8,
-  55296, 57343, 3,
-  57344, 57344, 3,
-  57344, 57344, 3,
-  64286, 64286, 4,
-  65024, 65039, 4,
-  65056, 65069, 4,
-  65279, 65279, 3,
-  65438, 65439, 4,
-  65520, 65528, 3,
-  65529, 65531, 3
+const CODE_POINT_BLOCKS = const [
+  0,
+  9,
+  3,
+  10,
+  10,
+  2,
+  11,
+  12,
+  3,
+  13,
+  13,
+  1,
+  14,
+  31,
+  3,
+  127,
+  159,
+  3,
+  173,
+  173,
+  3,
+  768,
+  879,
+  4,
+  1155,
+  1159,
+  4,
+  1160,
+  1161,
+  4,
+  1425,
+  1469,
+  4,
+  1471,
+  1471,
+  4,
+  1473,
+  1474,
+  4,
+  1476,
+  1477,
+  4,
+  1479,
+  1479,
+  4,
+  1536,
+  1541,
+  3,
+  1552,
+  1562,
+  4,
+  1564,
+  1564,
+  3,
+  1611,
+  1631,
+  4,
+  1648,
+  1648,
+  4,
+  1750,
+  1756,
+  4,
+  1757,
+  1757,
+  3,
+  1759,
+  1764,
+  4,
+  1767,
+  1768,
+  4,
+  1770,
+  1773,
+  4,
+  1807,
+  1807,
+  3,
+  1809,
+  1809,
+  4,
+  1840,
+  1866,
+  4,
+  1958,
+  1968,
+  4,
+  2027,
+  2035,
+  4,
+  2070,
+  2073,
+  4,
+  2075,
+  2083,
+  4,
+  2085,
+  2087,
+  4,
+  2089,
+  2093,
+  4,
+  2137,
+  2139,
+  4,
+  2276,
+  2306,
+  4,
+  2307,
+  2307,
+  5,
+  2362,
+  2362,
+  4,
+  2363,
+  2363,
+  5,
+  2364,
+  2364,
+  4,
+  2366,
+  2368,
+  5,
+  2369,
+  2376,
+  4,
+  2377,
+  2380,
+  5,
+  2381,
+  2381,
+  4,
+  2382,
+  2383,
+  5,
+  2385,
+  2391,
+  4,
+  2402,
+  2403,
+  4,
+  2433,
+  2433,
+  4,
+  2434,
+  2435,
+  5,
+  2492,
+  2492,
+  4,
+  2494,
+  2494,
+  4,
+  2495,
+  2496,
+  5,
+  2497,
+  2500,
+  4,
+  2503,
+  2504,
+  5,
+  2507,
+  2508,
+  5,
+  2509,
+  2509,
+  4,
+  2519,
+  2519,
+  4,
+  2530,
+  2531,
+  4,
+  2561,
+  2562,
+  4,
+  2563,
+  2563,
+  5,
+  2620,
+  2620,
+  4,
+  2622,
+  2624,
+  5,
+  2625,
+  2626,
+  4,
+  2631,
+  2632,
+  4,
+  2635,
+  2637,
+  4,
+  2641,
+  2641,
+  4,
+  2672,
+  2673,
+  4,
+  2677,
+  2677,
+  4,
+  2689,
+  2690,
+  4,
+  2691,
+  2691,
+  5,
+  2748,
+  2748,
+  4,
+  2750,
+  2752,
+  5,
+  2753,
+  2757,
+  4,
+  2759,
+  2760,
+  4,
+  2761,
+  2761,
+  5,
+  2763,
+  2764,
+  5,
+  2765,
+  2765,
+  4,
+  2786,
+  2787,
+  4,
+  2817,
+  2817,
+  4,
+  2818,
+  2819,
+  5,
+  2876,
+  2876,
+  4,
+  2878,
+  2878,
+  4,
+  2879,
+  2879,
+  4,
+  2880,
+  2880,
+  5,
+  2881,
+  2884,
+  4,
+  2887,
+  2888,
+  5,
+  2891,
+  2892,
+  5,
+  2893,
+  2893,
+  4,
+  2902,
+  2902,
+  4,
+  2903,
+  2903,
+  4,
+  2914,
+  2915,
+  4,
+  2946,
+  2946,
+  4,
+  3006,
+  3006,
+  4,
+  3007,
+  3007,
+  5,
+  3008,
+  3008,
+  4,
+  3009,
+  3010,
+  5,
+  3014,
+  3016,
+  5,
+  3018,
+  3020,
+  5,
+  3021,
+  3021,
+  4,
+  3031,
+  3031,
+  4,
+  3072,
+  3072,
+  4,
+  3073,
+  3075,
+  5,
+  3134,
+  3136,
+  4,
+  3137,
+  3140,
+  5,
+  3142,
+  3144,
+  4,
+  3146,
+  3149,
+  4,
+  3157,
+  3158,
+  4,
+  3170,
+  3171,
+  4,
+  3201,
+  3201,
+  4,
+  3202,
+  3203,
+  5,
+  3260,
+  3260,
+  4,
+  3262,
+  3262,
+  5,
+  3263,
+  3263,
+  4,
+  3264,
+  3265,
+  5,
+  3266,
+  3266,
+  4,
+  3267,
+  3268,
+  5,
+  3270,
+  3270,
+  4,
+  3271,
+  3272,
+  5,
+  3274,
+  3275,
+  5,
+  3276,
+  3277,
+  4,
+  3285,
+  3286,
+  4,
+  3298,
+  3299,
+  4,
+  3329,
+  3329,
+  4,
+  3330,
+  3331,
+  5,
+  3390,
+  3390,
+  4,
+  3391,
+  3392,
+  5,
+  3393,
+  3396,
+  4,
+  3398,
+  3400,
+  5,
+  3402,
+  3404,
+  5,
+  3405,
+  3405,
+  4,
+  3415,
+  3415,
+  4,
+  3426,
+  3427,
+  4,
+  3458,
+  3459,
+  5,
+  3530,
+  3530,
+  4,
+  3535,
+  3535,
+  4,
+  3536,
+  3537,
+  5,
+  3538,
+  3540,
+  4,
+  3542,
+  3542,
+  4,
+  3544,
+  3550,
+  5,
+  3551,
+  3551,
+  4,
+  3570,
+  3571,
+  5,
+  3633,
+  3633,
+  4,
+  3635,
+  3635,
+  5,
+  3636,
+  3642,
+  4,
+  3655,
+  3662,
+  4,
+  3761,
+  3761,
+  4,
+  3763,
+  3763,
+  5,
+  3764,
+  3769,
+  4,
+  3771,
+  3772,
+  4,
+  3784,
+  3789,
+  4,
+  3864,
+  3865,
+  4,
+  3893,
+  3893,
+  4,
+  3895,
+  3895,
+  4,
+  3897,
+  3897,
+  4,
+  3902,
+  3903,
+  5,
+  3953,
+  3966,
+  4,
+  3967,
+  3967,
+  5,
+  3968,
+  3972,
+  4,
+  3974,
+  3975,
+  4,
+  3981,
+  3991,
+  4,
+  3993,
+  4028,
+  4,
+  4038,
+  4038,
+  4,
+  4127,
+  4127,
+  4,
+  4141,
+  4144,
+  4,
+  4142,
+  4142,
+  4,
+  4145,
+  4145,
+  5,
+  4146,
+  4151,
+  4,
+  4153,
+  4154,
+  4,
+  4155,
+  4156,
+  5,
+  4157,
+  4158,
+  4,
+  4182,
+  4183,
+  5,
+  4184,
+  4185,
+  4,
+  4190,
+  4192,
+  4,
+  4209,
+  4212,
+  4,
+  4226,
+  4226,
+  4,
+  4228,
+  4228,
+  5,
+  4229,
+  4230,
+  4,
+  4237,
+  4237,
+  4,
+  4253,
+  4253,
+  4,
+  4259,
+  4259,
+  4,
+  4352,
+  4352,
+  5,
+  4352,
+  4447,
+  6,
+  4352,
+  4352,
+  4,
+  4352,
+  4352,
+  5,
+  4360,
+  4360,
+  5,
+  4363,
+  4363,
+  3,
+  4370,
+  4370,
+  5,
+  4375,
+  4375,
+  4,
+  4376,
+  4376,
+  5,
+  4387,
+  4387,
+  4,
+  4387,
+  4387,
+  5,
+  4397,
+  4397,
+  4,
+  4400,
+  4400,
+  4,
+  4403,
+  4403,
+  5,
+  4403,
+  4403,
+  4,
+  4403,
+  4403,
+  4,
+  4404,
+  4404,
+  4,
+  4405,
+  4405,
+  4,
+  4427,
+  4427,
+  5,
+  4427,
+  4427,
+  4,
+  4427,
+  4427,
+  5,
+  4427,
+  4427,
+  4,
+  4427,
+  4427,
+  4,
+  4428,
+  4428,
+  5,
+  4442,
+  4442,
+  4,
+  4443,
+  4443,
+  5,
+  4448,
+  4519,
+  7,
+  4451,
+  4451,
+  5,
+  4451,
+  4451,
+  4,
+  4458,
+  4458,
+  4,
+  4458,
+  4458,
+  5,
+  4458,
+  4458,
+  4,
+  4459,
+  4459,
+  4,
+  4459,
+  4459,
+  5,
+  4520,
+  4607,
+  8,
+  4957,
+  4959,
+  4,
+  5906,
+  5908,
+  4,
+  5938,
+  5940,
+  4,
+  5970,
+  5971,
+  4,
+  6002,
+  6003,
+  4,
+  6068,
+  6069,
+  4,
+  6070,
+  6070,
+  5,
+  6071,
+  6077,
+  4,
+  6078,
+  6085,
+  5,
+  6086,
+  6086,
+  4,
+  6087,
+  6088,
+  5,
+  6089,
+  6099,
+  4,
+  6109,
+  6109,
+  4,
+  6155,
+  6157,
+  4,
+  6158,
+  6158,
+  3,
+  6313,
+  6313,
+  4,
+  6432,
+  6434,
+  4,
+  6435,
+  6438,
+  5,
+  6439,
+  6440,
+  4,
+  6441,
+  6443,
+  5,
+  6448,
+  6449,
+  5,
+  6450,
+  6450,
+  4,
+  6451,
+  6456,
+  5,
+  6457,
+  6459,
+  4,
+  6581,
+  6583,
+  5,
+  6586,
+  6586,
+  5,
+  6679,
+  6680,
+  4,
+  6681,
+  6682,
+  5,
+  6683,
+  6683,
+  4,
+  6741,
+  6741,
+  5,
+  6742,
+  6742,
+  4,
+  6743,
+  6743,
+  5,
+  6744,
+  6750,
+  4,
+  6752,
+  6752,
+  4,
+  6754,
+  6754,
+  4,
+  6757,
+  6764,
+  4,
+  6765,
+  6770,
+  5,
+  6771,
+  6780,
+  4,
+  6783,
+  6783,
+  4,
+  6832,
+  6845,
+  4,
+  6846,
+  6846,
+  4,
+  6912,
+  6915,
+  4,
+  6916,
+  6916,
+  5,
+  6964,
+  6964,
+  4,
+  6965,
+  6965,
+  5,
+  6966,
+  6970,
+  4,
+  6971,
+  6971,
+  5,
+  6972,
+  6972,
+  4,
+  6973,
+  6977,
+  5,
+  6978,
+  6978,
+  4,
+  6979,
+  6980,
+  5,
+  7019,
+  7027,
+  4,
+  7040,
+  7041,
+  4,
+  7042,
+  7042,
+  5,
+  7073,
+  7073,
+  5,
+  7074,
+  7077,
+  4,
+  7078,
+  7079,
+  5,
+  7080,
+  7081,
+  4,
+  7082,
+  7082,
+  5,
+  7083,
+  7085,
+  4,
+  7142,
+  7142,
+  4,
+  7143,
+  7143,
+  5,
+  7144,
+  7145,
+  4,
+  7146,
+  7148,
+  5,
+  7149,
+  7149,
+  4,
+  7150,
+  7150,
+  5,
+  7151,
+  7153,
+  4,
+  7154,
+  7155,
+  5,
+  7204,
+  7211,
+  5,
+  7212,
+  7219,
+  4,
+  7220,
+  7221,
+  5,
+  7222,
+  7223,
+  4,
+  7376,
+  7378,
+  4,
+  7380,
+  7392,
+  4,
+  7393,
+  7393,
+  5,
+  7394,
+  7400,
+  4,
+  7405,
+  7405,
+  4,
+  7410,
+  7411,
+  5,
+  7412,
+  7412,
+  4,
+  7416,
+  7417,
+  4,
+  7446,
+  7446,
+  4,
+  7446,
+  7446,
+  5,
+  7446,
+  7446,
+  5,
+  7616,
+  7669,
+  4,
+  7676,
+  7679,
+  4,
+  8203,
+  8203,
+  3,
+  8204,
+  8205,
+  4,
+  8206,
+  8207,
+  3,
+  8232,
+  8232,
+  3,
+  8233,
+  8233,
+  3,
+  8234,
+  8238,
+  3,
+  8288,
+  8292,
+  3,
+  8293,
+  8293,
+  3,
+  8294,
+  8303,
+  3,
+  8400,
+  8412,
+  4,
+  8413,
+  8416,
+  4,
+  8417,
+  8417,
+  4,
+  8418,
+  8420,
+  4,
+  8421,
+  8432,
+  4,
+  11503,
+  11505,
+  4,
+  11647,
+  11647,
+  4,
+  11744,
+  11775,
+  4,
+  12330,
+  12333,
+  4,
+  12334,
+  12335,
+  4,
+  12441,
+  12442,
+  4,
+  42607,
+  42607,
+  4,
+  42608,
+  42610,
+  4,
+  42612,
+  42621,
+  4,
+  42655,
+  42655,
+  4,
+  42736,
+  42737,
+  4,
+  43010,
+  43010,
+  4,
+  43014,
+  43014,
+  4,
+  43019,
+  43019,
+  4,
+  43043,
+  43044,
+  5,
+  43045,
+  43046,
+  4,
+  43047,
+  43047,
+  5,
+  43136,
+  43137,
+  5,
+  43188,
+  43203,
+  5,
+  43204,
+  43204,
+  4,
+  43232,
+  43249,
+  4,
+  43302,
+  43309,
+  4,
+  43335,
+  43345,
+  4,
+  43346,
+  43347,
+  5,
+  43360,
+  43388,
+  6,
+  43392,
+  43394,
+  4,
+  43395,
+  43395,
+  5,
+  43443,
+  43443,
+  4,
+  43444,
+  43445,
+  5,
+  43446,
+  43449,
+  4,
+  43450,
+  43451,
+  5,
+  43452,
+  43452,
+  4,
+  43453,
+  43456,
+  5,
+  43493,
+  43493,
+  4,
+  43561,
+  43566,
+  4,
+  43567,
+  43568,
+  5,
+  43569,
+  43570,
+  4,
+  43571,
+  43572,
+  5,
+  43573,
+  43574,
+  4,
+  43587,
+  43587,
+  4,
+  43596,
+  43596,
+  4,
+  43597,
+  43597,
+  5,
+  43644,
+  43644,
+  4,
+  43696,
+  43696,
+  4,
+  43698,
+  43700,
+  4,
+  43703,
+  43704,
+  4,
+  43710,
+  43711,
+  4,
+  43713,
+  43713,
+  4,
+  43755,
+  43755,
+  5,
+  43756,
+  43757,
+  4,
+  43758,
+  43759,
+  5,
+  43765,
+  43765,
+  5,
+  43766,
+  43766,
+  4,
+  44003,
+  44004,
+  5,
+  44005,
+  44005,
+  4,
+  44006,
+  44007,
+  5,
+  44008,
+  44008,
+  4,
+  44009,
+  44010,
+  5,
+  44012,
+  44012,
+  5,
+  44013,
+  44013,
+  4,
+  44032,
+  44032,
+  9,
+  44033,
+  44059,
+  10,
+  44060,
+  44060,
+  9,
+  44061,
+  44087,
+  10,
+  44088,
+  44088,
+  9,
+  44089,
+  44115,
+  10,
+  44116,
+  44116,
+  9,
+  44117,
+  44143,
+  10,
+  44144,
+  44144,
+  9,
+  44145,
+  44171,
+  10,
+  44172,
+  44172,
+  9,
+  44173,
+  44199,
+  10,
+  44200,
+  44200,
+  9,
+  44201,
+  44227,
+  10,
+  44228,
+  44228,
+  9,
+  44229,
+  44255,
+  10,
+  44256,
+  44256,
+  9,
+  44257,
+  44283,
+  10,
+  44284,
+  44284,
+  9,
+  44285,
+  44311,
+  10,
+  44312,
+  44312,
+  9,
+  44313,
+  44339,
+  10,
+  44340,
+  44340,
+  9,
+  44341,
+  44367,
+  10,
+  44368,
+  44368,
+  9,
+  44369,
+  44395,
+  10,
+  44396,
+  44396,
+  9,
+  44397,
+  44423,
+  10,
+  44424,
+  44424,
+  9,
+  44425,
+  44451,
+  10,
+  44452,
+  44452,
+  9,
+  44453,
+  44479,
+  10,
+  44480,
+  44480,
+  9,
+  44481,
+  44507,
+  10,
+  44508,
+  44508,
+  9,
+  44509,
+  44535,
+  10,
+  44536,
+  44536,
+  9,
+  44537,
+  44563,
+  10,
+  44564,
+  44564,
+  9,
+  44565,
+  44591,
+  10,
+  44592,
+  44592,
+  9,
+  44593,
+  44619,
+  10,
+  44620,
+  44620,
+  9,
+  44621,
+  44647,
+  10,
+  44648,
+  44648,
+  9,
+  44649,
+  44675,
+  10,
+  44676,
+  44676,
+  9,
+  44677,
+  44703,
+  10,
+  44704,
+  44704,
+  9,
+  44705,
+  44731,
+  10,
+  44732,
+  44732,
+  9,
+  44733,
+  44759,
+  10,
+  44760,
+  44760,
+  9,
+  44761,
+  44787,
+  10,
+  44788,
+  44788,
+  9,
+  44789,
+  44815,
+  10,
+  44816,
+  44816,
+  9,
+  44817,
+  44843,
+  10,
+  44844,
+  44844,
+  9,
+  44845,
+  44871,
+  10,
+  44872,
+  44872,
+  9,
+  44873,
+  44899,
+  10,
+  44900,
+  44900,
+  9,
+  44901,
+  44927,
+  10,
+  44928,
+  44928,
+  9,
+  44929,
+  44955,
+  10,
+  44956,
+  44956,
+  9,
+  44957,
+  44983,
+  10,
+  44984,
+  44984,
+  9,
+  44985,
+  45011,
+  10,
+  45012,
+  45012,
+  9,
+  45013,
+  45039,
+  10,
+  45040,
+  45040,
+  9,
+  45041,
+  45067,
+  10,
+  45068,
+  45068,
+  9,
+  45069,
+  45095,
+  10,
+  45096,
+  45096,
+  9,
+  45097,
+  45123,
+  10,
+  45124,
+  45124,
+  9,
+  45125,
+  45151,
+  10,
+  45152,
+  45152,
+  9,
+  45153,
+  45179,
+  10,
+  45180,
+  45180,
+  9,
+  45181,
+  45207,
+  10,
+  45208,
+  45208,
+  9,
+  45209,
+  45235,
+  10,
+  45236,
+  45236,
+  9,
+  45237,
+  45263,
+  10,
+  45264,
+  45264,
+  9,
+  45265,
+  45291,
+  10,
+  45292,
+  45292,
+  9,
+  45293,
+  45319,
+  10,
+  45320,
+  45320,
+  9,
+  45321,
+  45347,
+  10,
+  45348,
+  45348,
+  9,
+  45349,
+  45375,
+  10,
+  45376,
+  45376,
+  9,
+  45377,
+  45403,
+  10,
+  45404,
+  45404,
+  9,
+  45405,
+  45431,
+  10,
+  45432,
+  45432,
+  9,
+  45433,
+  45459,
+  10,
+  45460,
+  45460,
+  9,
+  45461,
+  45487,
+  10,
+  45488,
+  45488,
+  9,
+  45489,
+  45515,
+  10,
+  45516,
+  45516,
+  9,
+  45517,
+  45543,
+  10,
+  45544,
+  45544,
+  9,
+  45545,
+  45571,
+  10,
+  45572,
+  45572,
+  9,
+  45573,
+  45599,
+  10,
+  45600,
+  45600,
+  9,
+  45601,
+  45627,
+  10,
+  45628,
+  45628,
+  9,
+  45629,
+  45655,
+  10,
+  45656,
+  45656,
+  9,
+  45657,
+  45683,
+  10,
+  45684,
+  45684,
+  9,
+  45685,
+  45711,
+  10,
+  45712,
+  45712,
+  9,
+  45713,
+  45739,
+  10,
+  45740,
+  45740,
+  9,
+  45741,
+  45767,
+  10,
+  45768,
+  45768,
+  9,
+  45769,
+  45795,
+  10,
+  45796,
+  45796,
+  9,
+  45797,
+  45823,
+  10,
+  45824,
+  45824,
+  9,
+  45825,
+  45851,
+  10,
+  45852,
+  45852,
+  9,
+  45853,
+  45879,
+  10,
+  45880,
+  45880,
+  9,
+  45881,
+  45907,
+  10,
+  45908,
+  45908,
+  9,
+  45909,
+  45935,
+  10,
+  45936,
+  45936,
+  9,
+  45937,
+  45963,
+  10,
+  45964,
+  45964,
+  9,
+  45965,
+  45991,
+  10,
+  45992,
+  45992,
+  9,
+  45993,
+  46019,
+  10,
+  46020,
+  46020,
+  9,
+  46021,
+  46047,
+  10,
+  46048,
+  46048,
+  9,
+  46049,
+  46075,
+  10,
+  46076,
+  46076,
+  9,
+  46077,
+  46103,
+  10,
+  46104,
+  46104,
+  9,
+  46105,
+  46131,
+  10,
+  46132,
+  46132,
+  9,
+  46133,
+  46159,
+  10,
+  46160,
+  46160,
+  9,
+  46161,
+  46187,
+  10,
+  46188,
+  46188,
+  9,
+  46189,
+  46215,
+  10,
+  46216,
+  46216,
+  9,
+  46217,
+  46243,
+  10,
+  46244,
+  46244,
+  9,
+  46245,
+  46271,
+  10,
+  46272,
+  46272,
+  9,
+  46273,
+  46299,
+  10,
+  46300,
+  46300,
+  9,
+  46301,
+  46327,
+  10,
+  46328,
+  46328,
+  9,
+  46329,
+  46355,
+  10,
+  46356,
+  46356,
+  9,
+  46357,
+  46383,
+  10,
+  46384,
+  46384,
+  9,
+  46385,
+  46411,
+  10,
+  46412,
+  46412,
+  9,
+  46413,
+  46439,
+  10,
+  46440,
+  46440,
+  9,
+  46441,
+  46467,
+  10,
+  46468,
+  46468,
+  9,
+  46469,
+  46495,
+  10,
+  46496,
+  46496,
+  9,
+  46497,
+  46523,
+  10,
+  46524,
+  46524,
+  9,
+  46525,
+  46551,
+  10,
+  46552,
+  46552,
+  9,
+  46553,
+  46579,
+  10,
+  46580,
+  46580,
+  9,
+  46581,
+  46607,
+  10,
+  46608,
+  46608,
+  9,
+  46609,
+  46635,
+  10,
+  46636,
+  46636,
+  9,
+  46637,
+  46663,
+  10,
+  46664,
+  46664,
+  9,
+  46665,
+  46691,
+  10,
+  46692,
+  46692,
+  9,
+  46693,
+  46719,
+  10,
+  46720,
+  46720,
+  9,
+  46721,
+  46747,
+  10,
+  46748,
+  46748,
+  9,
+  46749,
+  46775,
+  10,
+  46776,
+  46776,
+  9,
+  46777,
+  46803,
+  10,
+  46804,
+  46804,
+  9,
+  46805,
+  46831,
+  10,
+  46832,
+  46832,
+  9,
+  46833,
+  46859,
+  10,
+  46860,
+  46860,
+  9,
+  46861,
+  46887,
+  10,
+  46888,
+  46888,
+  9,
+  46889,
+  46915,
+  10,
+  46916,
+  46916,
+  9,
+  46917,
+  46943,
+  10,
+  46944,
+  46944,
+  9,
+  46945,
+  46971,
+  10,
+  46972,
+  46972,
+  9,
+  46973,
+  46999,
+  10,
+  47000,
+  47000,
+  9,
+  47001,
+  47027,
+  10,
+  47028,
+  47028,
+  9,
+  47029,
+  47055,
+  10,
+  47056,
+  47056,
+  9,
+  47057,
+  47083,
+  10,
+  47084,
+  47084,
+  9,
+  47085,
+  47111,
+  10,
+  47112,
+  47112,
+  9,
+  47113,
+  47139,
+  10,
+  47140,
+  47140,
+  9,
+  47141,
+  47167,
+  10,
+  47168,
+  47168,
+  9,
+  47169,
+  47195,
+  10,
+  47196,
+  47196,
+  9,
+  47197,
+  47223,
+  10,
+  47224,
+  47224,
+  9,
+  47225,
+  47251,
+  10,
+  47252,
+  47252,
+  9,
+  47253,
+  47279,
+  10,
+  47280,
+  47280,
+  9,
+  47281,
+  47307,
+  10,
+  47308,
+  47308,
+  9,
+  47309,
+  47335,
+  10,
+  47336,
+  47336,
+  9,
+  47337,
+  47363,
+  10,
+  47364,
+  47364,
+  9,
+  47365,
+  47391,
+  10,
+  47392,
+  47392,
+  9,
+  47393,
+  47419,
+  10,
+  47420,
+  47420,
+  9,
+  47421,
+  47447,
+  10,
+  47448,
+  47448,
+  9,
+  47449,
+  47475,
+  10,
+  47476,
+  47476,
+  9,
+  47477,
+  47503,
+  10,
+  47504,
+  47504,
+  9,
+  47505,
+  47531,
+  10,
+  47532,
+  47532,
+  9,
+  47533,
+  47559,
+  10,
+  47560,
+  47560,
+  9,
+  47561,
+  47587,
+  10,
+  47588,
+  47588,
+  9,
+  47589,
+  47615,
+  10,
+  47616,
+  47616,
+  9,
+  47617,
+  47643,
+  10,
+  47644,
+  47644,
+  9,
+  47645,
+  47671,
+  10,
+  47672,
+  47672,
+  9,
+  47673,
+  47699,
+  10,
+  47700,
+  47700,
+  9,
+  47701,
+  47727,
+  10,
+  47728,
+  47728,
+  9,
+  47729,
+  47755,
+  10,
+  47756,
+  47756,
+  9,
+  47757,
+  47783,
+  10,
+  47784,
+  47784,
+  9,
+  47785,
+  47811,
+  10,
+  47812,
+  47812,
+  9,
+  47813,
+  47839,
+  10,
+  47840,
+  47840,
+  9,
+  47841,
+  47867,
+  10,
+  47868,
+  47868,
+  9,
+  47869,
+  47895,
+  10,
+  47896,
+  47896,
+  9,
+  47897,
+  47923,
+  10,
+  47924,
+  47924,
+  9,
+  47925,
+  47951,
+  10,
+  47952,
+  47952,
+  9,
+  47953,
+  47979,
+  10,
+  47980,
+  47980,
+  9,
+  47981,
+  48007,
+  10,
+  48008,
+  48008,
+  9,
+  48009,
+  48035,
+  10,
+  48036,
+  48036,
+  9,
+  48037,
+  48063,
+  10,
+  48064,
+  48064,
+  9,
+  48065,
+  48091,
+  10,
+  48092,
+  48092,
+  9,
+  48093,
+  48119,
+  10,
+  48120,
+  48120,
+  9,
+  48121,
+  48147,
+  10,
+  48148,
+  48148,
+  9,
+  48149,
+  48175,
+  10,
+  48176,
+  48176,
+  9,
+  48177,
+  48203,
+  10,
+  48204,
+  48204,
+  9,
+  48205,
+  48231,
+  10,
+  48232,
+  48232,
+  9,
+  48233,
+  48259,
+  10,
+  48260,
+  48260,
+  9,
+  48261,
+  48287,
+  10,
+  48288,
+  48288,
+  9,
+  48289,
+  48315,
+  10,
+  48316,
+  48316,
+  9,
+  48317,
+  48343,
+  10,
+  48344,
+  48344,
+  9,
+  48345,
+  48371,
+  10,
+  48372,
+  48372,
+  9,
+  48373,
+  48399,
+  10,
+  48400,
+  48400,
+  9,
+  48401,
+  48427,
+  10,
+  48428,
+  48428,
+  9,
+  48429,
+  48455,
+  10,
+  48456,
+  48456,
+  9,
+  48457,
+  48483,
+  10,
+  48484,
+  48484,
+  9,
+  48485,
+  48511,
+  10,
+  48512,
+  48512,
+  9,
+  48513,
+  48539,
+  10,
+  48540,
+  48540,
+  9,
+  48541,
+  48567,
+  10,
+  48568,
+  48568,
+  9,
+  48569,
+  48595,
+  10,
+  48596,
+  48596,
+  9,
+  48597,
+  48623,
+  10,
+  48624,
+  48624,
+  9,
+  48625,
+  48651,
+  10,
+  48652,
+  48652,
+  9,
+  48653,
+  48679,
+  10,
+  48680,
+  48680,
+  9,
+  48681,
+  48707,
+  10,
+  48708,
+  48708,
+  9,
+  48709,
+  48735,
+  10,
+  48736,
+  48736,
+  9,
+  48737,
+  48763,
+  10,
+  48764,
+  48764,
+  9,
+  48765,
+  48791,
+  10,
+  48792,
+  48792,
+  9,
+  48793,
+  48819,
+  10,
+  48820,
+  48820,
+  9,
+  48821,
+  48847,
+  10,
+  48848,
+  48848,
+  9,
+  48849,
+  48875,
+  10,
+  48876,
+  48876,
+  9,
+  48877,
+  48903,
+  10,
+  48904,
+  48904,
+  9,
+  48905,
+  48931,
+  10,
+  48932,
+  48932,
+  9,
+  48933,
+  48959,
+  10,
+  48960,
+  48960,
+  9,
+  48961,
+  48987,
+  10,
+  48988,
+  48988,
+  9,
+  48989,
+  49015,
+  10,
+  49016,
+  49016,
+  9,
+  49017,
+  49043,
+  10,
+  49044,
+  49044,
+  9,
+  49045,
+  49071,
+  10,
+  49072,
+  49072,
+  9,
+  49073,
+  49099,
+  10,
+  49100,
+  49100,
+  9,
+  49101,
+  49127,
+  10,
+  49128,
+  49128,
+  9,
+  49129,
+  49155,
+  10,
+  49156,
+  49156,
+  9,
+  49157,
+  49183,
+  10,
+  49184,
+  49184,
+  9,
+  49185,
+  49211,
+  10,
+  49212,
+  49212,
+  9,
+  49213,
+  49239,
+  10,
+  49240,
+  49240,
+  9,
+  49241,
+  49267,
+  10,
+  49268,
+  49268,
+  9,
+  49269,
+  49295,
+  10,
+  49296,
+  49296,
+  9,
+  49297,
+  49323,
+  10,
+  49324,
+  49324,
+  9,
+  49325,
+  49351,
+  10,
+  49352,
+  49352,
+  9,
+  49353,
+  49379,
+  10,
+  49380,
+  49380,
+  9,
+  49381,
+  49407,
+  10,
+  49408,
+  49408,
+  9,
+  49409,
+  49435,
+  10,
+  49436,
+  49436,
+  9,
+  49437,
+  49463,
+  10,
+  49464,
+  49464,
+  9,
+  49465,
+  49491,
+  10,
+  49492,
+  49492,
+  9,
+  49493,
+  49519,
+  10,
+  49520,
+  49520,
+  9,
+  49521,
+  49547,
+  10,
+  49548,
+  49548,
+  9,
+  49549,
+  49575,
+  10,
+  49576,
+  49576,
+  9,
+  49577,
+  49603,
+  10,
+  49604,
+  49604,
+  9,
+  49605,
+  49631,
+  10,
+  49632,
+  49632,
+  9,
+  49633,
+  49659,
+  10,
+  49660,
+  49660,
+  9,
+  49661,
+  49687,
+  10,
+  49688,
+  49688,
+  9,
+  49689,
+  49715,
+  10,
+  49716,
+  49716,
+  9,
+  49717,
+  49743,
+  10,
+  49744,
+  49744,
+  9,
+  49745,
+  49771,
+  10,
+  49772,
+  49772,
+  9,
+  49773,
+  49799,
+  10,
+  49800,
+  49800,
+  9,
+  49801,
+  49827,
+  10,
+  49828,
+  49828,
+  9,
+  49829,
+  49855,
+  10,
+  49856,
+  49856,
+  9,
+  49857,
+  49883,
+  10,
+  49884,
+  49884,
+  9,
+  49885,
+  49911,
+  10,
+  49912,
+  49912,
+  9,
+  49913,
+  49939,
+  10,
+  49940,
+  49940,
+  9,
+  49941,
+  49967,
+  10,
+  49968,
+  49968,
+  9,
+  49969,
+  49995,
+  10,
+  49996,
+  49996,
+  9,
+  49997,
+  50023,
+  10,
+  50024,
+  50024,
+  9,
+  50025,
+  50051,
+  10,
+  50052,
+  50052,
+  9,
+  50053,
+  50079,
+  10,
+  50080,
+  50080,
+  9,
+  50081,
+  50107,
+  10,
+  50108,
+  50108,
+  9,
+  50109,
+  50135,
+  10,
+  50136,
+  50136,
+  9,
+  50137,
+  50163,
+  10,
+  50164,
+  50164,
+  9,
+  50165,
+  50191,
+  10,
+  50192,
+  50192,
+  9,
+  50193,
+  50219,
+  10,
+  50220,
+  50220,
+  9,
+  50221,
+  50247,
+  10,
+  50248,
+  50248,
+  9,
+  50249,
+  50275,
+  10,
+  50276,
+  50276,
+  9,
+  50277,
+  50303,
+  10,
+  50304,
+  50304,
+  9,
+  50305,
+  50331,
+  10,
+  50332,
+  50332,
+  9,
+  50333,
+  50359,
+  10,
+  50360,
+  50360,
+  9,
+  50361,
+  50387,
+  10,
+  50388,
+  50388,
+  9,
+  50389,
+  50415,
+  10,
+  50416,
+  50416,
+  9,
+  50417,
+  50443,
+  10,
+  50444,
+  50444,
+  9,
+  50445,
+  50471,
+  10,
+  50472,
+  50472,
+  9,
+  50473,
+  50499,
+  10,
+  50500,
+  50500,
+  9,
+  50501,
+  50527,
+  10,
+  50528,
+  50528,
+  9,
+  50529,
+  50555,
+  10,
+  50556,
+  50556,
+  9,
+  50557,
+  50583,
+  10,
+  50584,
+  50584,
+  9,
+  50585,
+  50611,
+  10,
+  50612,
+  50612,
+  9,
+  50613,
+  50639,
+  10,
+  50640,
+  50640,
+  9,
+  50641,
+  50667,
+  10,
+  50668,
+  50668,
+  9,
+  50669,
+  50695,
+  10,
+  50696,
+  50696,
+  9,
+  50697,
+  50723,
+  10,
+  50724,
+  50724,
+  9,
+  50725,
+  50751,
+  10,
+  50752,
+  50752,
+  9,
+  50753,
+  50779,
+  10,
+  50780,
+  50780,
+  9,
+  50781,
+  50807,
+  10,
+  50808,
+  50808,
+  9,
+  50809,
+  50835,
+  10,
+  50836,
+  50836,
+  9,
+  50837,
+  50863,
+  10,
+  50864,
+  50864,
+  9,
+  50865,
+  50891,
+  10,
+  50892,
+  50892,
+  9,
+  50893,
+  50919,
+  10,
+  50920,
+  50920,
+  9,
+  50921,
+  50947,
+  10,
+  50948,
+  50948,
+  9,
+  50949,
+  50975,
+  10,
+  50976,
+  50976,
+  9,
+  50977,
+  51003,
+  10,
+  51004,
+  51004,
+  9,
+  51005,
+  51031,
+  10,
+  51032,
+  51032,
+  9,
+  51033,
+  51059,
+  10,
+  51060,
+  51060,
+  9,
+  51061,
+  51087,
+  10,
+  51088,
+  51088,
+  9,
+  51089,
+  51115,
+  10,
+  51116,
+  51116,
+  9,
+  51117,
+  51143,
+  10,
+  51144,
+  51144,
+  9,
+  51145,
+  51171,
+  10,
+  51172,
+  51172,
+  9,
+  51173,
+  51199,
+  10,
+  51200,
+  51200,
+  9,
+  51201,
+  51227,
+  10,
+  51228,
+  51228,
+  9,
+  51229,
+  51255,
+  10,
+  51256,
+  51256,
+  9,
+  51257,
+  51283,
+  10,
+  51284,
+  51284,
+  9,
+  51285,
+  51311,
+  10,
+  51312,
+  51312,
+  9,
+  51313,
+  51339,
+  10,
+  51340,
+  51340,
+  9,
+  51341,
+  51367,
+  10,
+  51368,
+  51368,
+  9,
+  51369,
+  51395,
+  10,
+  51396,
+  51396,
+  9,
+  51397,
+  51423,
+  10,
+  51424,
+  51424,
+  9,
+  51425,
+  51451,
+  10,
+  51452,
+  51452,
+  9,
+  51453,
+  51479,
+  10,
+  51480,
+  51480,
+  9,
+  51481,
+  51507,
+  10,
+  51508,
+  51508,
+  9,
+  51509,
+  51535,
+  10,
+  51536,
+  51536,
+  9,
+  51537,
+  51563,
+  10,
+  51564,
+  51564,
+  9,
+  51565,
+  51591,
+  10,
+  51592,
+  51592,
+  9,
+  51593,
+  51619,
+  10,
+  51620,
+  51620,
+  9,
+  51621,
+  51647,
+  10,
+  51648,
+  51648,
+  9,
+  51649,
+  51675,
+  10,
+  51676,
+  51676,
+  9,
+  51677,
+  51703,
+  10,
+  51704,
+  51704,
+  9,
+  51705,
+  51731,
+  10,
+  51732,
+  51732,
+  9,
+  51733,
+  51759,
+  10,
+  51760,
+  51760,
+  9,
+  51761,
+  51787,
+  10,
+  51788,
+  51788,
+  9,
+  51789,
+  51815,
+  10,
+  51816,
+  51816,
+  9,
+  51817,
+  51843,
+  10,
+  51844,
+  51844,
+  9,
+  51845,
+  51871,
+  10,
+  51872,
+  51872,
+  9,
+  51873,
+  51899,
+  10,
+  51900,
+  51900,
+  9,
+  51901,
+  51927,
+  10,
+  51928,
+  51928,
+  9,
+  51929,
+  51955,
+  10,
+  51956,
+  51956,
+  9,
+  51957,
+  51983,
+  10,
+  51984,
+  51984,
+  9,
+  51985,
+  52011,
+  10,
+  52012,
+  52012,
+  9,
+  52013,
+  52039,
+  10,
+  52040,
+  52040,
+  9,
+  52041,
+  52067,
+  10,
+  52068,
+  52068,
+  9,
+  52069,
+  52095,
+  10,
+  52096,
+  52096,
+  9,
+  52097,
+  52123,
+  10,
+  52124,
+  52124,
+  9,
+  52125,
+  52151,
+  10,
+  52152,
+  52152,
+  9,
+  52153,
+  52179,
+  10,
+  52180,
+  52180,
+  9,
+  52181,
+  52207,
+  10,
+  52208,
+  52208,
+  9,
+  52209,
+  52235,
+  10,
+  52236,
+  52236,
+  9,
+  52237,
+  52263,
+  10,
+  52264,
+  52264,
+  9,
+  52265,
+  52291,
+  10,
+  52292,
+  52292,
+  9,
+  52293,
+  52319,
+  10,
+  52320,
+  52320,
+  9,
+  52321,
+  52347,
+  10,
+  52348,
+  52348,
+  9,
+  52349,
+  52375,
+  10,
+  52376,
+  52376,
+  9,
+  52377,
+  52403,
+  10,
+  52404,
+  52404,
+  9,
+  52405,
+  52431,
+  10,
+  52432,
+  52432,
+  9,
+  52433,
+  52459,
+  10,
+  52460,
+  52460,
+  9,
+  52461,
+  52487,
+  10,
+  52488,
+  52488,
+  9,
+  52489,
+  52515,
+  10,
+  52516,
+  52516,
+  9,
+  52517,
+  52543,
+  10,
+  52544,
+  52544,
+  9,
+  52545,
+  52571,
+  10,
+  52572,
+  52572,
+  9,
+  52573,
+  52599,
+  10,
+  52600,
+  52600,
+  9,
+  52601,
+  52627,
+  10,
+  52628,
+  52628,
+  9,
+  52629,
+  52655,
+  10,
+  52656,
+  52656,
+  9,
+  52657,
+  52683,
+  10,
+  52684,
+  52684,
+  9,
+  52685,
+  52711,
+  10,
+  52712,
+  52712,
+  9,
+  52713,
+  52739,
+  10,
+  52740,
+  52740,
+  9,
+  52741,
+  52767,
+  10,
+  52768,
+  52768,
+  9,
+  52769,
+  52795,
+  10,
+  52796,
+  52796,
+  9,
+  52797,
+  52823,
+  10,
+  52824,
+  52824,
+  9,
+  52825,
+  52851,
+  10,
+  52852,
+  52852,
+  9,
+  52853,
+  52879,
+  10,
+  52880,
+  52880,
+  9,
+  52881,
+  52907,
+  10,
+  52908,
+  52908,
+  9,
+  52909,
+  52935,
+  10,
+  52936,
+  52936,
+  9,
+  52937,
+  52963,
+  10,
+  52964,
+  52964,
+  9,
+  52965,
+  52991,
+  10,
+  52992,
+  52992,
+  9,
+  52993,
+  53019,
+  10,
+  53020,
+  53020,
+  9,
+  53021,
+  53047,
+  10,
+  53048,
+  53048,
+  9,
+  53049,
+  53075,
+  10,
+  53076,
+  53076,
+  9,
+  53077,
+  53103,
+  10,
+  53104,
+  53104,
+  9,
+  53105,
+  53131,
+  10,
+  53132,
+  53132,
+  9,
+  53133,
+  53159,
+  10,
+  53160,
+  53160,
+  9,
+  53161,
+  53187,
+  10,
+  53188,
+  53188,
+  9,
+  53189,
+  53215,
+  10,
+  53216,
+  53216,
+  9,
+  53217,
+  53243,
+  10,
+  53244,
+  53244,
+  9,
+  53245,
+  53271,
+  10,
+  53272,
+  53272,
+  9,
+  53273,
+  53299,
+  10,
+  53300,
+  53300,
+  9,
+  53301,
+  53327,
+  10,
+  53328,
+  53328,
+  9,
+  53329,
+  53355,
+  10,
+  53356,
+  53356,
+  9,
+  53357,
+  53383,
+  10,
+  53384,
+  53384,
+  9,
+  53385,
+  53411,
+  10,
+  53412,
+  53412,
+  9,
+  53413,
+  53439,
+  10,
+  53440,
+  53440,
+  9,
+  53441,
+  53467,
+  10,
+  53468,
+  53468,
+  9,
+  53469,
+  53495,
+  10,
+  53496,
+  53496,
+  9,
+  53497,
+  53523,
+  10,
+  53524,
+  53524,
+  9,
+  53525,
+  53551,
+  10,
+  53552,
+  53552,
+  9,
+  53553,
+  53579,
+  10,
+  53580,
+  53580,
+  9,
+  53581,
+  53607,
+  10,
+  53608,
+  53608,
+  9,
+  53609,
+  53635,
+  10,
+  53636,
+  53636,
+  9,
+  53637,
+  53663,
+  10,
+  53664,
+  53664,
+  9,
+  53665,
+  53691,
+  10,
+  53692,
+  53692,
+  9,
+  53693,
+  53719,
+  10,
+  53720,
+  53720,
+  9,
+  53721,
+  53747,
+  10,
+  53748,
+  53748,
+  9,
+  53749,
+  53775,
+  10,
+  53776,
+  53776,
+  9,
+  53777,
+  53803,
+  10,
+  53804,
+  53804,
+  9,
+  53805,
+  53831,
+  10,
+  53832,
+  53832,
+  9,
+  53833,
+  53859,
+  10,
+  53860,
+  53860,
+  9,
+  53861,
+  53887,
+  10,
+  53888,
+  53888,
+  9,
+  53889,
+  53915,
+  10,
+  53916,
+  53916,
+  9,
+  53917,
+  53943,
+  10,
+  53944,
+  53944,
+  9,
+  53945,
+  53971,
+  10,
+  53972,
+  53972,
+  9,
+  53973,
+  53999,
+  10,
+  54000,
+  54000,
+  9,
+  54001,
+  54027,
+  10,
+  54028,
+  54028,
+  9,
+  54029,
+  54055,
+  10,
+  54056,
+  54056,
+  9,
+  54057,
+  54083,
+  10,
+  54084,
+  54084,
+  9,
+  54085,
+  54111,
+  10,
+  54112,
+  54112,
+  9,
+  54113,
+  54139,
+  10,
+  54140,
+  54140,
+  9,
+  54141,
+  54167,
+  10,
+  54168,
+  54168,
+  9,
+  54169,
+  54195,
+  10,
+  54196,
+  54196,
+  9,
+  54197,
+  54223,
+  10,
+  54224,
+  54224,
+  9,
+  54225,
+  54251,
+  10,
+  54252,
+  54252,
+  9,
+  54253,
+  54279,
+  10,
+  54280,
+  54280,
+  9,
+  54281,
+  54307,
+  10,
+  54308,
+  54308,
+  9,
+  54309,
+  54335,
+  10,
+  54336,
+  54336,
+  9,
+  54337,
+  54363,
+  10,
+  54364,
+  54364,
+  9,
+  54365,
+  54391,
+  10,
+  54392,
+  54392,
+  9,
+  54393,
+  54419,
+  10,
+  54420,
+  54420,
+  9,
+  54421,
+  54447,
+  10,
+  54448,
+  54448,
+  9,
+  54449,
+  54475,
+  10,
+  54476,
+  54476,
+  9,
+  54477,
+  54503,
+  10,
+  54504,
+  54504,
+  9,
+  54505,
+  54531,
+  10,
+  54532,
+  54532,
+  9,
+  54533,
+  54559,
+  10,
+  54560,
+  54560,
+  9,
+  54561,
+  54587,
+  10,
+  54588,
+  54588,
+  9,
+  54589,
+  54615,
+  10,
+  54616,
+  54616,
+  9,
+  54617,
+  54643,
+  10,
+  54644,
+  54644,
+  9,
+  54645,
+  54671,
+  10,
+  54672,
+  54672,
+  9,
+  54673,
+  54699,
+  10,
+  54700,
+  54700,
+  9,
+  54701,
+  54727,
+  10,
+  54728,
+  54728,
+  9,
+  54729,
+  54755,
+  10,
+  54756,
+  54756,
+  9,
+  54757,
+  54783,
+  10,
+  54784,
+  54784,
+  9,
+  54785,
+  54811,
+  10,
+  54812,
+  54812,
+  9,
+  54813,
+  54839,
+  10,
+  54840,
+  54840,
+  9,
+  54841,
+  54867,
+  10,
+  54868,
+  54868,
+  9,
+  54869,
+  54895,
+  10,
+  54896,
+  54896,
+  9,
+  54897,
+  54923,
+  10,
+  54924,
+  54924,
+  9,
+  54925,
+  54951,
+  10,
+  54952,
+  54952,
+  9,
+  54953,
+  54979,
+  10,
+  54980,
+  54980,
+  9,
+  54981,
+  55007,
+  10,
+  55008,
+  55008,
+  9,
+  55009,
+  55035,
+  10,
+  55036,
+  55036,
+  9,
+  55037,
+  55063,
+  10,
+  55064,
+  55064,
+  9,
+  55065,
+  55091,
+  10,
+  55092,
+  55092,
+  9,
+  55093,
+  55119,
+  10,
+  55120,
+  55120,
+  9,
+  55121,
+  55147,
+  10,
+  55148,
+  55148,
+  9,
+  55149,
+  55175,
+  10,
+  55176,
+  55176,
+  9,
+  55177,
+  55203,
+  10,
+  55216,
+  55238,
+  7,
+  55243,
+  55291,
+  8,
+  55296,
+  57343,
+  3,
+  57344,
+  57344,
+  3,
+  57344,
+  57344,
+  3,
+  64286,
+  64286,
+  4,
+  65024,
+  65039,
+  4,
+  65056,
+  65069,
+  4,
+  65279,
+  65279,
+  3,
+  65438,
+  65439,
+  4,
+  65520,
+  65528,
+  3,
+  65529,
+  65531,
+  3
 ];
diff --git a/packages/charted/lib/core/text_metrics/segmentation_utils.dart b/packages/charted/lib/core/text_metrics/segmentation_utils.dart
index d3e724c..31d823c 100644
--- a/packages/charted/lib/core/text_metrics/segmentation_utils.dart
+++ b/packages/charted/lib/core/text_metrics/segmentation_utils.dart
@@ -10,7 +10,7 @@
 
 const CODE_CATEGORY_OTHER = 0;
 
-const CodeUnitCategory = const{
+const CodeUnitCategory = const {
   'Other': CODE_CATEGORY_OTHER,
   'CR': 1,
   'LF': 2,
diff --git a/packages/charted/lib/core/time_interval.dart b/packages/charted/lib/core/time_interval.dart
index 6385312..3f7119e 100644
--- a/packages/charted/lib/core/time_interval.dart
+++ b/packages/charted/lib/core/time_interval.dart
@@ -22,14 +22,13 @@
   DateTime floor(dynamic date) {
     assert(date is int || date is DateTime);
     if (date is int) {
-      date = new DateTime.fromMillisecondsSinceEpoch(date) ;
+      date = new DateTime.fromMillisecondsSinceEpoch(date);
     }
     return _floor(date);
   }
 
   DateTime round(dynamic date) {
-    DateTime d0 = floor(date),
-             d1 = offset(d0, 1);
+    DateTime d0 = floor(date), d1 = offset(d0, 1);
     int ms = date is int ? date : date.millisecondsSinceEpoch;
     return (ms - d0.millisecondsSinceEpoch < d1.millisecondsSinceEpoch - ms)
         ? d0
@@ -53,18 +52,15 @@
     if (dt > 1) {
       while (time.isBefore(t1)) {
         if ((_number(time) % dt) == 0) {
-          values.add(
-              new DateTime.fromMillisecondsSinceEpoch(
-                  time.millisecondsSinceEpoch));
+          values.add(new DateTime.fromMillisecondsSinceEpoch(
+              time.millisecondsSinceEpoch));
         }
         time = _step(time, 1);
       }
-    }
-    else {
+    } else {
       while (time.isBefore(t1)) {
-        values.add(
-            new DateTime.fromMillisecondsSinceEpoch(
-                time.millisecondsSinceEpoch));
+        values.add(new DateTime.fromMillisecondsSinceEpoch(
+            time.millisecondsSinceEpoch));
         time = _step(time, 1);
       }
     }
@@ -72,63 +68,78 @@
   }
 
   static TimeInterval second = new TimeInterval(
-      (DateTime date) =>
-          new DateTime.fromMillisecondsSinceEpoch(
-              (date.millisecondsSinceEpoch ~/ 1000) * 1000),
+      (DateTime date) => new DateTime.fromMillisecondsSinceEpoch(
+          (date.millisecondsSinceEpoch ~/ 1000) * 1000),
       (DateTime date, int offset) =>
           date = new DateTime.fromMillisecondsSinceEpoch(
               date.millisecondsSinceEpoch + offset * 1000),
       (DateTime date) => date.second);
 
   static TimeInterval minute = new TimeInterval(
-      (DateTime date) =>
-          new DateTime.fromMillisecondsSinceEpoch(
-              (date.millisecondsSinceEpoch ~/ 60000) * 60000),
+      (DateTime date) => new DateTime.fromMillisecondsSinceEpoch(
+          (date.millisecondsSinceEpoch ~/ 60000) * 60000),
       (DateTime date, int offset) =>
           date = new DateTime.fromMillisecondsSinceEpoch(
               date.millisecondsSinceEpoch + offset * 60000),
       (DateTime date) => date.minute);
 
   static TimeInterval hour = new TimeInterval(
-      (DateTime date) =>
-          new DateTime.fromMillisecondsSinceEpoch(
-              (date.millisecondsSinceEpoch ~/ 3600000) * 3600000),
+      (DateTime date) => new DateTime.fromMillisecondsSinceEpoch(
+          (date.millisecondsSinceEpoch ~/ 3600000) * 3600000),
       (DateTime date, int offset) =>
           date = new DateTime.fromMillisecondsSinceEpoch(
               date.millisecondsSinceEpoch + offset * 3600000),
       (DateTime date) => date.hour);
 
   static TimeInterval day = new TimeInterval(
-      (DateTime date) =>
-          new DateTime(date.year, date.month, date.day),
-      (DateTime date, int offset) =>
-          new DateTime(date.year, date.month, date.day + offset,
-              date.hour, date.minute, date.second, date.millisecond),
+      (DateTime date) => new DateTime(date.year, date.month, date.day),
+      (DateTime date, int offset) => new DateTime(
+          date.year,
+          date.month,
+          date.day + offset,
+          date.hour,
+          date.minute,
+          date.second,
+          date.millisecond),
       (DateTime date) => date.day - 1);
 
   static TimeInterval week = new TimeInterval(
       (DateTime date) =>
           new DateTime(date.year, date.month, date.day - (date.weekday % 7)),
-      (DateTime date, int offset) =>
-          new DateTime(date.year, date.month, date.day + offset * 7,
-              date.hour, date.minute, date.second, date.millisecond ),
-      (DateTime date) {
-        var day = year.floor(date).day;
-        return (dayOfYear(date) +  day % 7) ~/ 7;
-      });
+      (DateTime date, int offset) => new DateTime(
+          date.year,
+          date.month,
+          date.day + offset * 7,
+          date.hour,
+          date.minute,
+          date.second,
+          date.millisecond), (DateTime date) {
+    var day = year.floor(date).day;
+    return (dayOfYear(date) + day % 7) ~/ 7;
+  });
 
   static TimeInterval month = new TimeInterval(
       (DateTime date) => new DateTime(date.year, date.month, 1),
-      (DateTime date, num offset) =>
-          new DateTime(date.year, date.month + offset, date.day,
-              date.hour, date.minute, date.second, date.millisecond),
+      (DateTime date, num offset) => new DateTime(
+          date.year,
+          date.month + offset,
+          date.day,
+          date.hour,
+          date.minute,
+          date.second,
+          date.millisecond),
       (DateTime date) => date.month - 1);
 
   static TimeInterval year = new TimeInterval(
       (DateTime date) => new DateTime(date.year),
-      (DateTime date, num offset) =>
-          new DateTime(date.year + offset, date.month, date.day,
-              date.hour, date.minute, date.second, date.millisecond),
+      (DateTime date, num offset) => new DateTime(
+          date.year + offset,
+          date.month,
+          date.day,
+          date.hour,
+          date.minute,
+          date.second,
+          date.millisecond),
       (DateTime date) => date.year);
 
   static int dayOfYear(DateTime date) =>
diff --git a/packages/charted/lib/core/timer.dart b/packages/charted/lib/core/timer.dart
index a166631..93856dd 100644
--- a/packages/charted/lib/core/timer.dart
+++ b/packages/charted/lib/core/timer.dart
@@ -38,10 +38,10 @@
 
   /// Schedule a new [callback] to be called [delay] micro-seconds after
   /// [then] micro-seconds since epoch.
-  AnimationTimer(this.callback, { int delay: 0, int then: null })
+  AnimationTimer(this.callback, {int delay: 0, int then: null})
       : time = then == null
-          ? new DateTime.now().millisecondsSinceEpoch + delay
-          : then + delay {
+            ? new DateTime.now().millisecondsSinceEpoch + delay
+            : then + delay {
     _queue.add(this);
     if (!_animationFrameRequested) {
       if (_timerScheduled != null) {
@@ -59,7 +59,7 @@
     int earliest = null;
     AnimationTimer timer = _queue.isEmpty ? null : _queue.first;
 
-    while(timer != null) {
+    while (timer != null) {
       bool finished = false;
       AnimationTimer ref = timer;
 
@@ -83,15 +83,13 @@
 
     if (delay == null) {
       _animationFrameRequested = false;
-    }
-    else if (delay > 24) {
+    } else if (delay > 24) {
       if (_timerScheduled != null) {
         _timerScheduled.cancel();
       }
       _timerScheduled = new Timer(new Duration(milliseconds: delay), _step);
       _animationFrameRequested = false;
-    }
-    else {
+    } else {
       _animationFrameRequested = true;
       window.animationFrame.then(_step);
     }
diff --git a/packages/charted/lib/core/utils.dart b/packages/charted/lib/core/utils.dart
index febf9e6..abbdb1b 100644
--- a/packages/charted/lib/core/utils.dart
+++ b/packages/charted/lib/core/utils.dart
@@ -26,9 +26,9 @@
 part 'utils/rect.dart';
 part 'utils/bidi_formatter.dart';
 
-const String ORIENTATION_LEFT   = 'left';
-const String ORIENTATION_RIGHT  = 'right';
-const String ORIENTATION_TOP    = 'top';
+const String ORIENTATION_LEFT = 'left';
+const String ORIENTATION_RIGHT = 'right';
+const String ORIENTATION_TOP = 'top';
 const String ORIENTATION_BOTTOM = 'bottom';
 
 /// Identity function that returns the value passed as it's parameter.
diff --git a/packages/charted/lib/core/utils/bidi_formatter.dart b/packages/charted/lib/core/utils/bidi_formatter.dart
index 8b729ff..85df0c9 100644
--- a/packages/charted/lib/core/utils/bidi_formatter.dart
+++ b/packages/charted/lib/core/utils/bidi_formatter.dart
@@ -13,7 +13,7 @@
 
 /// Fix direction of HTML using <span dir="..."> for RTL when required
 fixMarkupDirection(String markup) =>
-    _bidiFormatter.wrapWithSpan(markup, isHtml:true);
+    _bidiFormatter.wrapWithSpan(markup, isHtml: true);
 
 /// Fix direction of text using unicode markers for RTL when required
 /// This is a simplified version of BidiFormatter.wrapWithUnicode that
diff --git a/packages/charted/lib/core/utils/color.dart b/packages/charted/lib/core/utils/color.dart
index bac12ec..5912a5e 100644
--- a/packages/charted/lib/core/utils/color.dart
+++ b/packages/charted/lib/core/utils/color.dart
@@ -17,9 +17,9 @@
   int _b = 0;
 
   // Internal representation of HSL
-  int _h = 0;   // 0 <= _h <= 360
-  int _s = 0;   // 0 <= _s <= 100
-  int _l = 0;   // 0 <= _l <= 100
+  int _h = 0; // 0 <= _h <= 360
+  int _s = 0; // 0 <= _s <= 100
+  int _l = 0; // 0 <= _l <= 100
 
   // Alpha value for this color
   double _a = 0.0;
@@ -33,33 +33,33 @@
 
   /// Create an instance using a string representing color in RGB color space.
   /// The input string, [value], can be one of the following formats:
-  /// 
+  ///
   ///    #RGB
   ///    #RRGGBB
-  ///    
+  ///
   ///    rgb(R, G, B)
   ///    rgba(R, G, B, A)
-  /// 
+  ///
   /// R, G and B represent intensities of Red, Green and Blue channels and A
   /// represents the alpha channel (transparency)
-  /// 
+  ///
   /// When using these formats:
   ///     0 <= R,G,B <= 255
   ///     0 <= A <= 1.0
   factory Color.fromRgbString(String value) =>
-      isHexColorString(value) ? _fromHexString(value) : _fromRgbString(value); 
-  
+      isHexColorString(value) ? _fromHexString(value) : _fromRgbString(value);
+
   /// Create an instance from HSL colors.
   Color.fromHsla(this._h, this._s, this._l, this._a) : _hasHslColors = true;
 
   /// Create an instance using a string representing color in HSL color space.
   /// The input string, [value], can be in one of the following formats:
-  /// 
+  ///
   ///     hsl(H, S%, L%)
   ///     hsla(H, S%, L%, A)
-  /// 
+  ///
   /// H, S and L represent Hue, Saturation and Luminosity respectively.
-  /// 
+  ///
   /// When using these formats:
   ///     0 <= H <= 360
   ///     0 <= S,L <= 100
@@ -249,12 +249,12 @@
 
   /// Tests if [str] is a color represented by hsl() or hsla()
   static bool isHslColorString(String str) => hslaColorRegExp.hasMatch(str);
-  
+
   /// Create an instance using the passed RGB string.
   static Color _fromRgbString(String value) {
-    int pos =
-        (value.startsWith('rgb(') || value.startsWith('RGB(')) ? 4 :
-        (value.startsWith('rgba(') || value.startsWith('RGBA(')) ? 5 : 0;
+    int pos = (value.startsWith('rgb(') || value.startsWith('RGB('))
+        ? 4
+        : (value.startsWith('rgba(') || value.startsWith('RGBA(')) ? 5 : 0;
     if (pos != 0) {
       final params = value.substring(pos, value.length - 1).split(',');
       int r = int.parse(params[0]),
@@ -278,10 +278,9 @@
     if (hex.length == 3) {
       for (final char in hex) {
         final val = int.parse(char, radix: 16);
-        rgb = (rgb * 16 + val ) * 16 + val;
+        rgb = (rgb * 16 + val) * 16 + val;
       }
-    }
-    else if (hex.length == 6){
+    } else if (hex.length == 6) {
       rgb = int.parse(hex, radix: 16);
     }
 
@@ -291,9 +290,9 @@
 
   /// Create an instance using the passed HSL color string.
   static Color _fromHslString(String value) {
-    int pos =
-        (value.startsWith('hsl(') || value.startsWith('HSL(')) ? 4 :
-        (value.startsWith('hsla(') || value.startsWith('HSLA(')) ? 5 : 0;
+    int pos = (value.startsWith('hsl(') || value.startsWith('HSL('))
+        ? 4
+        : (value.startsWith('hsla(') || value.startsWith('HSLA(')) ? 5 : 0;
     if (pos != 0) {
       final params = value.substring(pos, value.length - 1).split(',');
       int h = int.parse(params[0]),
diff --git a/packages/charted/lib/core/utils/lists.dart b/packages/charted/lib/core/utils/lists.dart
index d9633f9..3a5b05c 100644
--- a/packages/charted/lib/core/utils/lists.dart
+++ b/packages/charted/lib/core/utils/lists.dart
@@ -9,30 +9,30 @@
 part of charted.core.utils;
 
 /// Returns a sum of all values in the given list of values
-num sum(List values) =>
-    values == null || values.isEmpty ?
-        0: values.fold(0.0, (old, next) => old + next);
+num sum(List values) => values == null || values.isEmpty
+    ? 0
+    : values.fold(0.0, (old, next) => old + next);
 
 /// Returns the smallest number in the given list of values
-num min(Iterable values) =>
-    values == null || values.isEmpty ?
-        null : values.fold(values.elementAt(0), math.min);
+num min(Iterable values) => values == null || values.isEmpty
+    ? null
+    : values.fold(values.elementAt(0), math.min);
 
 /// Returns the largest number in the given list of values
-num max(Iterable values) =>
-    values == null || values.isEmpty ?
-        null : values.fold(values.elementAt(0), math.max);
+num max(Iterable values) => values == null || values.isEmpty
+    ? null
+    : values.fold(values.elementAt(0), math.max);
 
 /// Represents a constant pair of values
 class Pair<T1, T2> {
   final T1 first;
   final T2 last;
-  
+
   const Pair(this.first, this.last);
-  
-  bool operator==(other) =>
+
+  bool operator ==(other) =>
       other is Pair && first == other.first && last == other.last;
-  
+
   int get hashCode => hash2(first, last);
 }
 
@@ -42,10 +42,9 @@
   final T max;
 
   factory Extent.items(Iterable<T> items,
-      [ Comparator compare = Comparable.compare ]) {
+      [Comparator compare = Comparable.compare]) {
     if (items.length == 0) return new Extent(null, null);
-    var max = items.first,
-        min = items.first;
+    var max = items.first, min = items.first;
     for (var value in items) {
       if (compare(max, value) < 0) max = value;
       if (compare(min, value) > 0) min = value;
@@ -53,7 +52,10 @@
     return new Extent(min, max);
   }
 
-  const Extent(T min, T max) : min = min, max = max, super(min, max);
+  const Extent(T min, T max)
+      : min = min,
+        max = max,
+        super(min, max);
 }
 
 /// Iterable representing a range of values containing the start, stop
@@ -62,13 +64,13 @@
   final num start;
   final num stop;
   final num step;
-  
+
   factory Range.integers(num start, [num stop, num step = 1]) =>
       new Range(start, stop, step, true);
 
   factory Range(num start, [num stop, num step = 1, bool integers = false]) {
     List<num> values = <num>[];
-    
+
     if (stop == null) {
       stop = start;
       start = 0;
@@ -78,9 +80,7 @@
       throw new ArgumentError('Invalid range.');
     }
 
-    var k = _integerConversionFactor(step.abs()),
-        i = -1,
-        j;
+    var k = _integerConversionFactor(step.abs()), i = -1, j;
 
     start *= k;
     stop *= k;
@@ -95,10 +95,10 @@
         values.add(integers ? j ~/ k : j / k);
       }
     }
-    
+
     return new Range._internal(start, stop, step, values);
   }
-  
+
   Range._internal(this.start, this.stop, this.step, List values)
       : super(values);
 
diff --git a/packages/charted/lib/core/utils/namespace.dart b/packages/charted/lib/core/utils/namespace.dart
index 7d1d8d4..00af84c 100644
--- a/packages/charted/lib/core/utils/namespace.dart
+++ b/packages/charted/lib/core/utils/namespace.dart
@@ -13,7 +13,7 @@
 /// namespace.
 class Namespace {
   /// Supported namespace prefixes mapped to their URIs.
-  static const Map<String,String> NS_PREFIXES = const {
+  static const Map<String, String> NS_PREFIXES = const {
     "svg": "http://www.w3.org/2000/svg",
     "xhtml": "http://www.w3.org/1999/xhtml",
     "xlink": "http://www.w3.org/1999/xlink",
@@ -30,10 +30,10 @@
       return parent.ownerDocument.createElementNS(parent.namespaceUri, tag);
     }
     Namespace parsed = new Namespace._internal(tag, separatorIndex);
-    return parsed.namespaceUri == null ?
-        parent.ownerDocument.createElementNS(parent.namespaceUri, tag) :
-        parent.ownerDocument.createElementNS(parsed.namespaceUri,
-            parsed.localName);
+    return parsed.namespaceUri == null
+        ? parent.ownerDocument.createElementNS(parent.namespaceUri, tag)
+        : parent.ownerDocument
+            .createElementNS(parsed.namespaceUri, parsed.localName);
   }
 
   /// Local part of the Element's tag name.
diff --git a/packages/charted/lib/core/utils/object_factory.dart b/packages/charted/lib/core/utils/object_factory.dart
index 7ddab07..465ac18 100644
--- a/packages/charted/lib/core/utils/object_factory.dart
+++ b/packages/charted/lib/core/utils/object_factory.dart
@@ -30,8 +30,7 @@
     if (!_components.containsKey(name)) {
       throw new ArgumentError('Element $name not found in ComponentFactory');
     }
-    var creator = _components[name],
-        instance = creator();
+    var creator = _components[name], instance = creator();
     if (instance == null) {
       throw new ArgumentError('Component $name initialization failed.');
     }
diff --git a/packages/charted/lib/core/utils/rect.dart b/packages/charted/lib/core/utils/rect.dart
index 628a4b5..3e666ee 100644
--- a/packages/charted/lib/core/utils/rect.dart
+++ b/packages/charted/lib/core/utils/rect.dart
@@ -16,11 +16,12 @@
   final num height;
 
   const Rect([this.x = 0, this.y = 0, this.width = 0, this.height = 0]);
-  const Rect.size(this.width, this.height) : x = 0, y = 0;
-  const Rect.position(this.x, this.y) : width = 0, height = 0;
-
-  bool operator==(other) =>
-      other is Rect && isSameSizeAs(other) && isSamePositionAs(other);
+  const Rect.size(this.width, this.height)
+      : x = 0,
+        y = 0;
+  const Rect.position(this.x, this.y)
+      : width = 0,
+        height = 0;
 
   bool isSameSizeAs(Rect other) =>
       other != null && width == other.width && height == other.height;
@@ -29,10 +30,16 @@
       other != null && x == other.x && y == other.y;
 
   bool contains(num otherX, num otherY) =>
-      otherX >= x && otherX <= x + width &&
-      otherY >= y && otherY <= y + height;
+      otherX >= x && otherX <= x + width && otherY >= y && otherY <= y + height;
 
   String toString() => '$x, $y, $width, $height';
+
+  @override
+  bool operator ==(other) =>
+      other is Rect && isSameSizeAs(other) && isSamePositionAs(other);
+
+  @override
+  int get hashCode => hash4(x, y, width, height);
 }
 
 /// Mutable version of [Rect] class.
@@ -55,8 +62,13 @@
 
   const AbsoluteRect(this.top, this.end, this.bottom, this.start);
 
-  bool operator==(other) =>
-      other is AbsoluteRect &&
-      start == other.start && end == other.end &&
-      top == other.top && bottom == other.bottom;
-}
\ No newline at end of file
+  @override
+  bool operator ==(other) => other is AbsoluteRect &&
+      start == other.start &&
+      end == other.end &&
+      top == other.top &&
+      bottom == other.bottom;
+
+  @override
+  int get hashCode => hash4(start, end, top, bottom);
+}
diff --git a/packages/charted/lib/layout/src/hierarchy_layout.dart b/packages/charted/lib/layout/src/hierarchy_layout.dart
index 81cbcbc..9997ab0 100644
--- a/packages/charted/lib/layout/src/hierarchy_layout.dart
+++ b/packages/charted/lib/layout/src/hierarchy_layout.dart
@@ -26,8 +26,8 @@
   /// parentColumn and valueColumn which is used to construct the hierarchy.
   /// The returned list of nodes contains the hierarchy with root being the
   /// first element its children in depth first order.
-  List<T> layout(List rows, int parentColumn, int labelColumn,
-      int valueColumn) {
+  List<T> layout(
+      List rows, int parentColumn, int labelColumn, int valueColumn) {
     List<HierarchyNode> nodeList = [];
     for (var row in rows) {
       nodeList.add(createNode(row[labelColumn], row[valueColumn], 0));
@@ -38,8 +38,9 @@
       if (parentRow == ROOT_ROW_INDEX) continue;
       var currentNode = nodeList[i];
       var parentNode = nodeList[parentRow];
-      (parentNode.children.isEmpty) ? parentNode.children = [currentNode] :
-          parentNode.children.add(currentNode);
+      (parentNode.children.isEmpty)
+          ? parentNode.children = [currentNode]
+          : parentNode.children.add(currentNode);
       currentNode.parent = parentNode;
       currentNode.depth = parentNode.depth + 1;
       for (var child in currentNode.children) {
@@ -72,7 +73,6 @@
   /// Default sorting method for comparing node a and b.
   static int hierarchySort(HierarchyNode a, HierarchyNode b) =>
       b.value - a.value;
-
 }
 
 abstract class HierarchyNode {
diff --git a/packages/charted/lib/layout/src/pie_layout.dart b/packages/charted/lib/layout/src/pie_layout.dart
index 6d3382a..bb316af 100644
--- a/packages/charted/lib/layout/src/pie_layout.dart
+++ b/packages/charted/lib/layout/src/pie_layout.dart
@@ -43,8 +43,8 @@
    * arcs in a pie-chart or donut-chart.
    */
   List layout(List data, [int ei, Element e]) {
-    var values = new List.generate(data.length,
-            (int i) => accessor(data[i], i)),
+    var values =
+        new List.generate(data.length, (int i) => accessor(data[i], i)),
         startAngle = startAngleCallback(data, ei, e),
         endAngle = endAngleCallback(data, ei, e),
         total = sum(values),
@@ -67,12 +67,10 @@
   }
 
   /** Sets a constant value to start angle of the layout */
-  set startAngle(num value) =>
-      startAngleCallback = toCallback(value);
+  set startAngle(num value) => startAngleCallback = toCallback(value);
 
   /** Sets a constant value to end angle of the layout */
-  set endAngle(num value) =>
-      endAngleCallback = toCallback(value);
+  set endAngle(num value) => endAngleCallback = toCallback(value);
 
   /** Default value accessor */
   static num defaultValueAccessor(num d, i) => d;
diff --git a/packages/charted/lib/layout/src/treemap_layout.dart b/packages/charted/lib/layout/src/treemap_layout.dart
index 8f118ba..601d0d4 100644
--- a/packages/charted/lib/layout/src/treemap_layout.dart
+++ b/packages/charted/lib/layout/src/treemap_layout.dart
@@ -20,7 +20,7 @@
   static const TREEMAP_LAYOUT_SQUARIFY = 0;
 
   /// Horizontal subdivision.
-  static const TREEMAP_LAYOUT_SLICE= 1;
+  static const TREEMAP_LAYOUT_SLICE = 1;
 
   /// Vertical subdivision.
   static const TREEMAP_LAYOUT_DICE = 2;
@@ -49,14 +49,14 @@
 
   /// TODO(midoringo): Implement sticky related feature.
   get sticky => _sticky;
-  set sticky (bool sticky) {
+  set sticky(bool sticky) {
     _sticky = sticky;
   }
 
   // TODO (midoringo): handle the sticky case.
   @override
-  List<TreeMapNode> layout(List rows, int parentColumn, int labelColumn,
-      int valueColumn) {
+  List<TreeMapNode> layout(
+      List rows, int parentColumn, int labelColumn, int valueColumn) {
     var nodes = super.layout(rows, parentColumn, labelColumn, valueColumn);
     var root = nodes[0];
     root.x = 0;
@@ -71,9 +71,9 @@
   @override
   TreeMapNode createNode(label, value, depth) {
     return new TreeMapNode()
-        ..label = label
-        ..value = value
-        ..depth = depth;
+      ..label = label
+      ..value = value
+      ..depth = depth;
   }
 
   void _position(List<TreeMapNode> nodes, num length, MutableRect rect,
@@ -87,8 +87,8 @@
         node.x = x;
         node.y = y;
         node.dy = v;
-        x += node.dx = math.min(rect.x + rect.width - x, v > 0 ?
-            (node.area / v).round() : 0);
+        x += node.dx = math.min(
+            rect.x + rect.width - x, v > 0 ? (node.area / v).round() : 0);
       }
       nodes.last.sticky = true;
       nodes.last.dx += rect.x + rect.width - x;
@@ -100,8 +100,8 @@
         node.x = x;
         node.y = y;
         node.dx = v;
-        y += node.dy = math.min(rect.y + rect.height - y, v > 0 ?
-            (node.area / v).round() : 0);
+        y += node.dy = math.min(
+            rect.y + rect.height - y, v > 0 ? (node.area / v).round() : 0);
       }
       nodes.last.sticky = false;
       nodes.last.dy += rect.y + rect.height - y;
@@ -149,8 +149,10 @@
     }
     pArea *= pArea;
     length *= length;
-    return (pArea > 0) ? math.max(length * rmax * ratio / pArea,
-        pArea / (length * rmin * ratio)) : double.INFINITY;
+    return (pArea > 0)
+        ? math.max(
+            length * rmax * ratio / pArea, pArea / (length * rmin * ratio))
+        : double.INFINITY;
   }
 
   /// Recursively compute each nodes (and its children nodes) position and size
@@ -162,12 +164,16 @@
       List<TreeMapNode> nodes = [];
       var area = 0;
       var remaining = new List.from(children);
-      var score, n,
-      best = double.INFINITY,
-      length = (mode == TREEMAP_LAYOUT_SLICE) ? rect.width :
-          (mode == TREEMAP_LAYOUT_DICE) ? rect.height :
-          (mode == TREEMAP_LAYOUT_SLICE_DICE) ? (node.depth & 1 == 1) ?
-              rect.height : rect.width : math.min(rect.width, rect.height);
+      var score,
+          n,
+          best = double.INFINITY,
+          length = (mode == TREEMAP_LAYOUT_SLICE)
+              ? rect.width
+              : (mode == TREEMAP_LAYOUT_DICE)
+                  ? rect.height
+                  : (mode == TREEMAP_LAYOUT_SLICE_DICE)
+                      ? (node.depth & 1 == 1) ? rect.height : rect.width
+                      : math.min(rect.width, rect.height);
       _scale(remaining, rect.width * rect.height / node.value);
       while ((n = remaining.length) > 0) {
         var child = remaining[n - 1];
diff --git a/packages/charted/lib/locale/format.dart b/packages/charted/lib/locale/format.dart
index 64b4396..a61c405 100644
--- a/packages/charted/lib/locale/format.dart
+++ b/packages/charted/lib/locale/format.dart
@@ -35,14 +35,30 @@
   return locale.numberFormat.format(specifier);
 }
 
-
 /*
  * Class for computing the SI format prefix for the given value.
  */
 class FormatPrefix {
   // SI scale units in increments of 1000.
-  static const List unitPrefixes = const
-      ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
+  static const List unitPrefixes = const [
+    "y",
+    "z",
+    "a",
+    "f",
+    "p",
+    "n",
+    "µ",
+    "m",
+    "",
+    "k",
+    "M",
+    "G",
+    "T",
+    "P",
+    "E",
+    "Z",
+    "Y"
+  ];
 
   Function _scale;
   String _symbol;
@@ -58,8 +74,7 @@
 
     // Determining SI scale of the value in increment of 1000.
     i = 1 + (1e-12 + math.log(value) / math.LN10).floor();
-    i = math.max(-24, math.min(24,
-        ((i - 1) / 3).floor() * 3));
+    i = math.max(-24, math.min(24, ((i - 1) / 3).floor() * 3));
     i = 8 + (i / 3).floor();
 
     // Sets the scale and symbol of the value.
@@ -74,8 +89,7 @@
 
   /** Returns the value of x rounded to the nth digit. */
   _roundToPrecision(num x, num n) {
-    return n != 0 ?
-        (x * (n = math.pow(10, n))).round() / n : x.round();
+    return n != 0 ? (x * (n = math.pow(10, n))).round() / n : x.round();
   }
 
   /** Returns the SI prefix for the value. */
diff --git a/packages/charted/lib/locale/format/number_format.dart b/packages/charted/lib/locale/format/number_format.dart
index d1c97a7..5761e2b 100644
--- a/packages/charted/lib/locale/format/number_format.dart
+++ b/packages/charted/lib/locale/format/number_format.dart
@@ -14,11 +14,11 @@
  * specifier with the number properties of the locale.
  */
 class NumberFormat {
-
   // [[fill]align][sign][symbol][0][width][,][.precision][type]
-  static RegExp FORMAT_REGEX =
-      new RegExp(r'(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?'
-      r'(\.-?\d+)?([a-z%])?', caseSensitive: false);
+  static RegExp FORMAT_REGEX = new RegExp(
+      r'(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?'
+      r'(\.-?\d+)?([a-z%])?',
+      caseSensitive: false);
 
   String localeDecimal;
   String localeThousands;
@@ -31,24 +31,23 @@
     localeThousands = locale.thousands;
     localeGrouping = locale.grouping;
     localeCurrency = locale.currency;
-    formatGroup = (localeGrouping != null) ? (value) {
-      var i = value.length,
-          t = [],
-          j = 0,
-          g = localeGrouping[0];
-      while (i > 0 && g > 0) {
-        if (i - g >= 0) {
-          i = i - g;
-        } else {
-          g = i;
-          i = 0;
-        }
-        var length = (i + g) < value.length ? (i + g) : value.length;
-        t.add(value.substring(i, length));
-        g = localeGrouping[j = (j + 1) % localeGrouping.length];
-      }
-      return t.reversed.join(localeThousands);
-    } : (x) => x;
+    formatGroup = (localeGrouping != null)
+        ? (value) {
+            var i = value.length, t = [], j = 0, g = localeGrouping[0];
+            while (i > 0 && g > 0) {
+              if (i - g >= 0) {
+                i = i - g;
+              } else {
+                g = i;
+                i = 0;
+              }
+              var length = (i + g) < value.length ? (i + g) : value.length;
+              t.add(value.substring(i, length));
+              g = localeGrouping[j = (j + 1) % localeGrouping.length];
+            }
+            return t.reversed.join(localeThousands);
+          }
+        : (x) => x;
   }
 
   /**
@@ -70,8 +69,8 @@
         zfill = match.group(5),
         width = match.group(6) != null ? int.parse(match.group(6)) : 0,
         comma = match.group(7) != null,
-        precision = match.group(8) != null ?
-            int.parse(match.group(8).substring(1)) : null,
+        precision =
+        match.group(8) != null ? int.parse(match.group(8).substring(1)) : null,
         type = match.group(9),
         scale = 1,
         prefix = '',
@@ -87,16 +86,35 @@
     }
 
     switch (type) {
-      case 'n': comma = true; type = 'g'; break;
-      case '%': scale = 100; suffix = '%'; type = 'f'; break;
-      case 'p': scale = 100; suffix = '%'; type = 'r'; break;
+      case 'n':
+        comma = true;
+        type = 'g';
+        break;
+      case '%':
+        scale = 100;
+        suffix = '%';
+        type = 'f';
+        break;
+      case 'p':
+        scale = 100;
+        suffix = '%';
+        type = 'r';
+        break;
       case 'b':
       case 'o':
       case 'x':
-      case 'X': if (symbol == '#') prefix = '0' + type.toLowerCase(); break;
+      case 'X':
+        if (symbol == '#') prefix = '0' + type.toLowerCase();
+        break;
       case 'c':
-      case 'd': integer = true; precision = 0; break;
-      case 's': scale = -1; type = 'r'; break;
+      case 'd':
+        integer = true;
+        precision = 0;
+        break;
+      case 's':
+        scale = -1;
+        type = 'r';
+        break;
     }
 
     if (symbol == '\$') {
@@ -141,8 +159,8 @@
       // format.  Preserve the existing suffix, if any, such as the
       // currency symbol.
       if (scale < 0) {
-        FormatPrefix unit = new FormatPrefix(value,
-            (precision != null) ? precision : 0);
+        FormatPrefix unit =
+            new FormatPrefix(value, (precision != null) ? precision : 0);
         value = unit.scale(value);
         fullSuffix = unit.symbol + suffix;
       } else {
@@ -168,10 +186,13 @@
         before = formatGroup(before);
       }
 
-      var length = prefix.length + before.length + after.length +
+      var length = prefix.length +
+              before.length +
+              after.length +
               (zcomma ? 0 : negative.length),
-          padding = length < width ? new List.filled(
-              (length = width - length + 1), '').join(fill) : '';
+          padding = length < width
+              ? new List.filled((length = width - length + 1), '').join(fill)
+              : '';
 
       // If the fill character is '0', grouping is applied after padding.
       if (zcomma) {
@@ -185,17 +206,23 @@
       value = before + after;
 
       // Apply any padding and alignment attributes before returning the string.
-      return (align == '<' ? negative + value + padding
-          : align == '>' ? padding + negative + value
-          : align == '^' ? padding.substring(0, length >>= 1) + negative +
-              value + padding.substring(length)
-          : negative + (zcomma ? value : padding + value)) + fullSuffix;
+      return (align == '<'
+              ? negative + value + padding
+              : align == '>'
+                  ? padding + negative + value
+                  : align == '^'
+                      ? padding.substring(0, length >>= 1) +
+                          negative +
+                          value +
+                          padding.substring(length)
+                      : negative + (zcomma ? value : padding + value)) +
+          fullSuffix;
     };
   }
 
   // Gets the format function by given type.
   NumberFormatFunction _getFormatFunction(String type) {
-    switch(type) {
+    switch (type) {
       case 'b':
         return (num x, [int p = 0]) => x.toInt().toRadixString(2);
       case 'c':
@@ -218,4 +245,4 @@
         return (num x, [int p = 0]) => x.toString();
     }
   }
-}
\ No newline at end of file
+}
diff --git a/packages/charted/lib/locale/format/time_format.dart b/packages/charted/lib/locale/format/time_format.dart
index d2c16c6..d1b0e6b 100644
--- a/packages/charted/lib/locale/format/time_format.dart
+++ b/packages/charted/lib/locale/format/time_format.dart
@@ -19,8 +19,8 @@
   TimeFormat([String template = null, String identifier = 'en_US']) {
     _template = template;
     _locale = identifier;
-    if (_template != null)
-      _dateFormat = new DateFormat(_wrapStrptime2ICU(_template), _locale);
+    if (_template != null) _dateFormat =
+        new DateFormat(_wrapStrptime2ICU(_template), _locale);
   }
 
   TimeFormat _getInstance(String template) {
@@ -40,16 +40,13 @@
   }
 
   TimeFormatFunction multi(List<List> formats) {
-    var n = formats.length,
-        i = -1;
-    while (++i < n)
-      formats[i][0] = _getInstance(formats[i][0] as String);
+    var n = formats.length, i = -1;
+    while (++i < n) formats[i][0] = _getInstance(formats[i][0] as String);
     return (var date) {
       if (date is num) {
         date = new DateTime.fromMillisecondsSinceEpoch(date.toInt());
       }
-      var i = 0,
-          f = formats[i];
+      var i = 0, f = formats[i];
       while (f.length < 2 || f[1](date) == false) {
         i++;
         if (i < n) f = formats[i];
@@ -60,8 +57,8 @@
   }
 
   UTCTimeFormat utc([String specifier = null]) {
-    return new UTCTimeFormat(specifier == null ?
-        _template : specifier, _locale);
+    return new UTCTimeFormat(
+        specifier == null ? _template : specifier, _locale);
   }
 
   static UTCTimeFormat iso() {
@@ -77,7 +74,7 @@
     'B': 'MMMM',
     'c': 'EEE MMM d HH:mm:ss yyyy',
     'd': 'dd',
-    'e': 'd',         // TODO(songrenchu): zero padding not supported
+    'e': 'd', // TODO(songrenchu): zero padding not supported
     'H': 'HH',
     'I': 'hh',
     'j': 'DDD',
@@ -86,11 +83,11 @@
     'L': 'SSS',
     'p': 'a',
     'S': 'ss',
-    'U': 'ww',        // TODO(songrenchu): ICU doesn't distinguish 'U' and 'W',
-                      // and not supported by Dart: DateFormat
-    'w': 'ee',        // TODO(songrenchu): e not supported by Dart: DateFormat
-    'W': 'ww',        // TODO(songrenchu): ICU doesn't distinguish 'U' and 'W',
-                      // and not supported by Dart: DateFormat
+    'U': 'ww', // TODO(songrenchu): ICU doesn't distinguish 'U' and 'W',
+    // and not supported by Dart: DateFormat
+    'w': 'ee', // TODO(songrenchu): e not supported by Dart: DateFormat
+    'W': 'ww', // TODO(songrenchu): ICU doesn't distinguish 'U' and 'W',
+    // and not supported by Dart: DateFormat
     'x': 'MM/dd/yyyy',
     'X': 'HH:mm:ss',
     'y': 'yy',
@@ -100,30 +97,25 @@
   };
 
   String _wrapStrptime2ICU(String template) {
-    var string = [],
-        i = -1,
-        j = 0,
-        n = template.length,
-        tempChar;
+    var string = [], i = -1, j = 0, n = template.length, tempChar;
     while (++i < n) {
       if (template[i] == '%') {
         string.add(template.substring(j, i));
-        if ((timeFormatPads[tempChar = template[++i]]) != null)
-          tempChar = template[++i];
-        if (timeFormatsTransform[tempChar] != null)
-          string.add(timeFormatsTransform[tempChar]);
+        if ((timeFormatPads[tempChar = template[++i]]) != null) tempChar =
+            template[++i];
+        if (timeFormatsTransform[tempChar] != null) string
+            .add(timeFormatsTransform[tempChar]);
         j = i + 1;
       }
     }
-    if (j < i)
-      string.add("'" + template.substring(j, i) + "'");
+    if (j < i) string.add("'" + template.substring(j, i) + "'");
     return string.join("");
   }
 }
 
 class UTCTimeFormat extends TimeFormat {
-  UTCTimeFormat(String template, [String identifier = 'en_US']):
-    super(template, identifier);
+  UTCTimeFormat(String template, [String identifier = 'en_US'])
+      : super(template, identifier);
 
   UTCTimeFormat _getInstance(String template) {
     return new UTCTimeFormat(template, _locale);
@@ -133,4 +125,4 @@
     assert(_dateFormat != null);
     return _dateFormat.parseUTC(string);
   }
-}
\ No newline at end of file
+}
diff --git a/packages/charted/lib/locale/languages/en_us.dart b/packages/charted/lib/locale/languages/en_us.dart
index 53be549..7d6b354 100644
--- a/packages/charted/lib/locale/languages/en_us.dart
+++ b/packages/charted/lib/locale/languages/en_us.dart
@@ -23,22 +23,50 @@
   final identifier = 'en_US';
   final decimal = '.';
   final thousands = ',';
-  final grouping = const[3];
-  final currency = const['\$', ''];
+  final grouping = const [3];
+  final currency = const ['\$', ''];
   final dateTime = '%a %b %e %X %Y';
   final date = '%m/%d/%Y';
   final time = '%H =>%M =>%S';
-  final periods = const['AM', 'PM'];
+  final periods = const ['AM', 'PM'];
 
-  final days = const[
-      'Sunday', 'Monday', 'Tuesday',
-      'Wednesday', 'Thursday', 'Friday', 'Saturday'];
-  final shortDays = const['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+  final days = const [
+    'Sunday',
+    'Monday',
+    'Tuesday',
+    'Wednesday',
+    'Thursday',
+    'Friday',
+    'Saturday'
+  ];
+  final shortDays = const ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
 
-  final months = const[
-      'January', 'February', 'March', 'April', 'May', 'June',
-      'July', 'August', 'September', 'October', 'November', 'December'];
-  final shortMonths = const[
-      'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
-      'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+  final months = const [
+    'January',
+    'February',
+    'March',
+    'April',
+    'May',
+    'June',
+    'July',
+    'August',
+    'September',
+    'October',
+    'November',
+    'December'
+  ];
+  final shortMonths = const [
+    'Jan',
+    'Feb',
+    'Mar',
+    'Apr',
+    'May',
+    'Jun',
+    'Jul',
+    'Aug',
+    'Sep',
+    'Oct',
+    'Nov',
+    'Dec'
+  ];
 }
diff --git a/packages/charted/lib/selection/selection.dart b/packages/charted/lib/selection/selection.dart
index d040745..c9036dc 100644
--- a/packages/charted/lib/selection/selection.dart
+++ b/packages/charted/lib/selection/selection.dart
@@ -152,8 +152,8 @@
    * selection (with data associated to the element, index of the element in
    * it's group and the element itself) to get the value of the property.
    */
-  void styleWithCallback(String property,
-      SelectionCallback<String> fn, {String priority});
+  void styleWithCallback(String property, SelectionCallback<String> fn,
+      {String priority});
 
   /**
    * Sets textContent of all elements in the selection to [val]. A side-effect
@@ -262,8 +262,8 @@
    * it's group and the element itself) to get the data to be set on the
    * current element.
    */
-  DataSelection dataWithCallback(
-      SelectionCallback<Iterable> fn, [SelectionKeyFunction keyFn]);
+  DataSelection dataWithCallback(SelectionCallback<Iterable> fn,
+      [SelectionKeyFunction keyFn]);
 
   /**
    * Associates data with all the elements - no join is performed. Unlike
@@ -287,7 +287,6 @@
   Transition transition();
 }
 
-
 /*
  * Group of elements in the selection.
  * Each selection may contain more than one group of elements.
@@ -297,7 +296,6 @@
   Element parent;
 }
 
-
 /**
  * [EnterSelection] is a sub-selection that represents missing elements of a
  * selection - an element is considered missing when there is data and no
diff --git a/packages/charted/lib/selection/selection_scope.dart b/packages/charted/lib/selection/selection_scope.dart
index 3543f92..38d43f2 100644
--- a/packages/charted/lib/selection/selection_scope.dart
+++ b/packages/charted/lib/selection/selection_scope.dart
@@ -24,7 +24,7 @@
    * [selector] as the root.
    */
   SelectionScope.selector(String selector) {
-    if (selector == null || selector.isEmpty ){
+    if (selector == null || selector.isEmpty) {
       throw new ArgumentError('Selector cannot be empty');
     }
     _root = document.querySelector(selector);
@@ -74,7 +74,7 @@
    * elements in it.
    */
   Selection selectAll(String selector) =>
-      new _SelectionImpl.all(selector:selector, scope:this);
+      new _SelectionImpl.all(selector: selector, scope: this);
 
   /**
    * Creates a new [Selection] containing [elements].  Assumes that
diff --git a/packages/charted/lib/selection/src/selection_impl.dart b/packages/charted/lib/selection/src/selection_impl.dart
index 8604da7..14de177 100644
--- a/packages/charted/lib/selection/src/selection_impl.dart
+++ b/packages/charted/lib/selection/src/selection_impl.dart
@@ -13,7 +13,6 @@
  * the select or selectAll methods on [SelectionScope] and [Selection].
  */
 class _SelectionImpl implements Selection {
-
   Iterable<SelectionGroup> groups;
   SelectionScope scope;
 
@@ -30,15 +29,18 @@
    * "element" itself passed as parameters.  [fn] must return an iterable of
    * elements to be used in each group.
    */
-  _SelectionImpl.all({String selector, SelectionCallback<Iterable<Element>> fn,
-      SelectionScope this.scope, Selection source}) {
+  _SelectionImpl.all(
+      {String selector,
+      SelectionCallback<Iterable<Element>> fn,
+      SelectionScope this.scope,
+      Selection source}) {
     assert(selector != null || fn != null);
     assert(source != null || scope != null);
 
     if (selector != null) {
-      fn = (d, i, c) => c == null ?
-          scope.root.querySelectorAll(selector) :
-          c.querySelectorAll(selector);
+      fn = (d, i, c) => c == null
+          ? scope.root.querySelectorAll(selector)
+          : c.querySelectorAll(selector);
     }
 
     var tmpGroups = new List<SelectionGroup>();
@@ -50,14 +52,13 @@
           final e = g.elements.elementAt(ei);
           if (e != null) {
             tmpGroups.add(
-                new _SelectionGroupImpl(
-                    fn(scope.datum(e), gi, e), parent: e));
+                new _SelectionGroupImpl(fn(scope.datum(e), gi, e), parent: e));
           }
         }
       }
     } else {
-      tmpGroups.add(
-          new _SelectionGroupImpl(fn(null, 0, null), parent: scope.root));
+      tmpGroups
+          .add(new _SelectionGroupImpl(fn(null, 0, null), parent: scope.root));
     }
     groups = tmpGroups;
   }
@@ -67,15 +68,18 @@
    * [selector] is specified.  Otherwise, call [fn] which must return the
    * element to be selected.
    */
-  _SelectionImpl.single({String selector, SelectionCallback<Element> fn,
-      SelectionScope this.scope, Selection source}) {
+  _SelectionImpl.single(
+      {String selector,
+      SelectionCallback<Element> fn,
+      SelectionScope this.scope,
+      Selection source}) {
     assert(selector != null || fn != null);
     assert(source != null || scope != null);
 
     if (selector != null) {
-      fn = (d, i, c) => c == null ?
-          scope.root.querySelector(selector) :
-          c.querySelector(selector);
+      fn = (d, i, c) => c == null
+          ? scope.root.querySelector(selector)
+          : c.querySelector(selector);
     }
 
     if (source != null) {
@@ -84,23 +88,26 @@
         SelectionGroup g = source.groups.elementAt(gi);
         return new _SelectionGroupImpl(
             new List.generate(g.elements.length, (ei) {
-          var e = g.elements.elementAt(ei);
-          if (e != null) {
-            var datum = scope.datum(e);
-            var enterElement = fn(datum, ei, e);
-            if (datum != null) {
-              scope.associate(enterElement, datum);
-            }
-            return enterElement;
-          } else {
-            return null;
-          }
-        }), parent: g.parent);
+              var e = g.elements.elementAt(ei);
+              if (e != null) {
+                var datum = scope.datum(e);
+                var enterElement = fn(datum, ei, e);
+                if (datum != null) {
+                  scope.associate(enterElement, datum);
+                }
+                return enterElement;
+              } else {
+                return null;
+              }
+            }),
+            parent: g.parent);
       });
     } else {
-      groups = new List<SelectionGroup>.generate(1,
-          (_) => new _SelectionGroupImpl(new List.generate(1,
-              (_) => fn(null, 0, null), growable: false)), growable: false);
+      groups = new List<SelectionGroup>.generate(
+          1,
+          (_) => new _SelectionGroupImpl(
+              new List.generate(1, (_) => fn(null, 0, null), growable: false)),
+          growable: false);
     }
   }
 
@@ -113,8 +120,7 @@
    * be part of the same group, with [SelectionScope.root] as the group's parent
    */
   _SelectionImpl.elements(Iterable elements, SelectionScope this.scope) {
-    groups = new List<SelectionGroup>()
-        ..add(new _SelectionGroupImpl(elements));
+    groups = new List<SelectionGroup>()..add(new _SelectionGroupImpl(elements));
   }
 
   /**
@@ -140,19 +146,19 @@
 
   void on(String type, [SelectionCallback listener, bool capture]) {
     Function getEventHandler(i, e) => (Event event) {
-      var previous = scope.event;
-      scope.event = event;
-      try {
-        listener(scope.datum(e), i, e);
-      } finally {
-        scope.event = previous;
-      }
-    };
+          var previous = scope.event;
+          scope.event = event;
+          try {
+            listener(scope.datum(e), i, e);
+          } finally {
+            scope.event = previous;
+          }
+        };
 
     if (!type.startsWith('.')) {
       if (listener != null) {
         // Add a listener to each element.
-        each((d, i, Element e){
+        each((d, i, Element e) {
           var handlers = scope._listeners[e];
           if (handlers == null) scope._listeners[e] = handlers = {};
           handlers[type] = new Pair(getEventHandler(i, e), capture);
@@ -171,8 +177,7 @@
     } else {
       // Remove all listeners on the event type (ignoring the namespace)
       each((d, i, Element e) {
-        var handlers = scope._listeners[e],
-            t = type.substring(1);
+        var handlers = scope._listeners[e], t = type.substring(1);
         handlers.forEach((String s, Pair<Function, bool> value) {
           if (s.split('.')[0] == t) {
             e.removeEventListener(s, value.first, value.last);
@@ -210,8 +215,10 @@
 
   void attrWithCallback(String name, SelectionCallback fn) {
     assert(fn != null);
-    _do(fn, (e, v) => v == null ?
-        e.attributes.remove(name) : e.attributes[name] = "$v");
+    _do(
+        fn,
+        (e, v) =>
+            v == null ? e.attributes.remove(name) : e.attributes[name] = "$v");
   }
 
   void classed(String name, [bool val = true]) {
@@ -221,23 +228,23 @@
 
   void classedWithCallback(String name, SelectionCallback<bool> fn) {
     assert(fn != null);
-    _do(fn, (e, v) =>
-        v == false ? e.classes.remove(name) : e.classes.add(name));
+    _do(fn,
+        (e, v) => v == false ? e.classes.remove(name) : e.classes.add(name));
   }
 
   void style(String property, val, {String priority}) {
     assert(property != null && property.isNotEmpty);
-    styleWithCallback(property,
-        toCallback(val as String), priority: priority);
+    styleWithCallback(property, toCallback(val as String), priority: priority);
   }
 
-  void styleWithCallback(String property,
-      SelectionCallback<String> fn, {String priority}) {
+  void styleWithCallback(String property, SelectionCallback<String> fn,
+      {String priority}) {
     assert(fn != null);
-    _do(fn, (Element e, String v) =>
-        v == null || v.isEmpty ?
-            e.style.removeProperty(property) :
-            e.style.setProperty(property, v, priority));
+    _do(
+        fn,
+        (Element e, String v) => v == null || v.isEmpty
+            ? e.style.removeProperty(property)
+            : e.style.setProperty(property, v, priority));
   }
 
   void text(String val) => textWithCallback(toCallback(val));
@@ -263,7 +270,7 @@
 
   Selection selectWithCallback(SelectionCallback<Element> fn) {
     assert(fn != null);
-    return new _SelectionImpl.single(fn: fn, source:this);
+    return new _SelectionImpl.single(fn: fn, source: this);
   }
 
   Selection append(String tag) {
@@ -275,9 +282,9 @@
   Selection appendWithCallback(SelectionCallback<Element> fn) {
     assert(fn != null);
     return new _SelectionImpl.single(fn: (datum, ei, e) {
-          Element child = fn(datum, ei, e);
-          return child == null ? null : e.append(child);
-        }, source: this);
+      Element child = fn(datum, ei, e);
+      return child == null ? null : e.append(child);
+    }, source: this);
   }
 
   Selection insert(String tag,
@@ -285,7 +292,8 @@
     assert(tag != null && tag.isNotEmpty);
     return insertWithCallback(
         (d, ei, e) => Namespace.createChildElement(tag, e),
-        before: before, beforeFn: beforeFn);
+        before: before,
+        beforeFn: beforeFn);
   }
 
   Selection insertWithCallback(SelectionCallback<Element> fn,
@@ -293,13 +301,11 @@
     assert(fn != null);
     beforeFn =
         before == null ? beforeFn : (d, ei, e) => e.querySelector(before);
-    return new _SelectionImpl.single(
-        fn: (datum, ei, e) {
-          Element child = fn(datum, ei, e);
-          Element before = beforeFn(datum, ei, e);
-          return child == null ? null : e.insertBefore(child, before);
-        },
-        source: this);
+    return new _SelectionImpl.single(fn: (datum, ei, e) {
+      Element child = fn(datum, ei, e);
+      Element before = beforeFn(datum, ei, e);
+      return child == null ? null : e.insertBefore(child, before);
+    }, source: this);
   }
 
   Selection selectAll(String selector) {
@@ -309,7 +315,7 @@
 
   Selection selectAllWithCallback(SelectionCallback<Iterable<Element>> fn) {
     assert(fn != null);
-    return new _SelectionImpl.all(fn: fn, source:this);
+    return new _SelectionImpl.all(fn: fn, source: this);
   }
 
   DataSelection data(Iterable vals, [SelectionKeyFunction keyFn]) {
@@ -317,20 +323,19 @@
     return dataWithCallback(toCallback(vals), keyFn);
   }
 
-  DataSelection dataWithCallback(
-      SelectionCallback<Iterable> fn, [SelectionKeyFunction keyFn]) {
+  DataSelection dataWithCallback(SelectionCallback<Iterable> fn,
+      [SelectionKeyFunction keyFn]) {
     assert(fn != null);
 
-    var enterGroups = [],
-        updateGroups = [],
-        exitGroups = [];
+    var enterGroups = [], updateGroups = [], exitGroups = [];
 
     // Create a dummy node to be used with enter() selection.
     Object dummy(val) {
       var element = new Object();
       scope.associate(element, val);
       return element;
-    };
+    }
+    ;
 
     // Joins data to all elements in the group.
     void join(SelectionGroup g, Iterable vals) {
@@ -346,9 +351,7 @@
 
       // Use key function to determine DOMElement to data associations.
       if (keyFn != null) {
-        var keysOnDOM = [],
-            elementsByKey = {},
-            valuesByKey = {};
+        var keysOnDOM = [], elementsByKey = {}, valuesByKey = {};
 
         // Create a key to DOM element map.
         // Used later to see if an element already exists for a key.
@@ -419,15 +422,15 @@
       enterGroups.add(new _SelectionGroupImpl(enter, parent: g.parent));
       updateGroups.add(new _SelectionGroupImpl(update, parent: g.parent));
       exitGroups.add(new _SelectionGroupImpl(exit, parent: g.parent));
-    };
+    }
+    ;
 
     for (int gi = 0; gi < groups.length; ++gi) {
       final g = groups.elementAt(gi);
       join(g, fn(scope.datum(g.parent), gi, g.parent));
     }
 
-    return new _DataSelectionImpl(
-        updateGroups, enterGroups, exitGroups, scope);
+    return new _DataSelectionImpl(updateGroups, enterGroups, exitGroups, scope);
   }
 
   void datum(Iterable vals) {
@@ -447,7 +450,8 @@
   ExitSelection exit;
 
   _DataSelectionImpl(Iterable updated, Iterable entering, Iterable exiting,
-      SelectionScope scope) : super.selectionGroups(updated, scope) {
+      SelectionScope scope)
+      : super.selectionGroups(updated, scope) {
     enter = new _EnterSelectionImpl(entering, this);
     exit = new _ExitSelectionImpl(exiting, this);
   }
@@ -471,7 +475,8 @@
     assert(tag != null && tag.isNotEmpty);
     return insertWithCallback(
         (d, ei, e) => Namespace.createChildElement(tag, e),
-        before: before, beforeFn: beforeFn);
+        before: before,
+        beforeFn: beforeFn);
   }
 
   Selection insertWithCallback(SelectionCallback<Element> fn,
@@ -493,10 +498,10 @@
   Selection appendWithCallback(SelectionCallback<Element> fn) {
     assert(fn != null);
     return selectWithCallback((datum, ei, e) {
-          Element child = fn(datum, ei, e);
-          e.append(child);
-          return child;
-        });
+      Element child = fn(datum, ei, e);
+      e.append(child);
+      return child;
+    });
   }
 
   Selection select(String selector) {
@@ -513,8 +518,7 @@
       for (int ei = 0, eLen = g.elements.length; ei < eLen; ++ei) {
         final e = g.elements.elementAt(ei);
         if (e != null) {
-          var datum = scope.datum(e),
-              selected = fn(datum, ei, g.parent);
+          var datum = scope.datum(e), selected = fn(datum, ei, g.parent);
           scope.associate(selected, datum);
           u.elements[ei] = selected;
           subgroup.add(selected);
@@ -532,7 +536,8 @@
 class _ExitSelectionImpl extends _SelectionImpl implements ExitSelection {
   final DataSelection update;
   _ExitSelectionImpl(Iterable groups, DataSelection update)
-      : update = update, super.selectionGroups(groups, update.scope);
+      : update = update,
+        super.selectionGroups(groups, update.scope);
 }
 
 class _SelectionGroupImpl implements SelectionGroup {
diff --git a/packages/charted/lib/selection/src/transition_impl.dart b/packages/charted/lib/selection/src/transition_impl.dart
index 53bb72a..204f28c 100644
--- a/packages/charted/lib/selection/src/transition_impl.dart
+++ b/packages/charted/lib/selection/src/transition_impl.dart
@@ -13,8 +13,8 @@
 
 class _TransitionImpl implements Transition {
   SelectionCallback _delay = (d, i, c) => 0;
-  SelectionCallback _duration =
-      (d, i, c) => Transition.defaultDurationMilliseconds;
+  SelectionCallback _duration = (d, i, c) =>
+      Transition.defaultDurationMilliseconds;
   Selection _selection;
   Map _attrs = {};
   Map _styles = {};
@@ -32,8 +32,8 @@
     _timerDelay = delay;
   }
 
-  Interpolator ease = clampEasingFn(
-          Transition.defaultEasingMode(Transition.defaultEasingType));
+  Interpolator ease =
+      clampEasingFn(Transition.defaultEasingMode(Transition.defaultEasingType));
 
   void delay(int millisecond) {
     delayWithCallback(toCallback(millisecond));
@@ -84,27 +84,29 @@
       _selection.each((d, i, c) {
         var tweenList = [];
         _attrs.forEach((key, value) {
-            tweenList.add(_getAttrInterpolator(c, key, value(d, i, c)));
+          tweenList.add(_getAttrInterpolator(c, key, value(d, i, c)));
         });
         _attrTweens.forEach((key, value) {
-          tweenList.add((t) => c.setAttribute(key,
-              value(d, i, c.getAttribute(key))(t)));
+          tweenList.add(
+              (t) => c.setAttribute(key, value(d, i, c.getAttribute(key))(t)));
         });
         _styles.forEach((key, value) {
-            tweenList.add(_getStyleInterpolator(c, key,
-                value['callback'](d, i, c), value['priority']));
+          tweenList.add(_getStyleInterpolator(
+              c, key, value['callback'](d, i, c), value['priority']));
         });
         _styleTweens.forEach((key, value) {
-          tweenList.add((t) => c.style.setProperty(key,
-              value['callback'](d, i,
-              c.style.getPropertyValue(key))(t).toString(), value['priority']));
+          tweenList.add((t) => c.style.setProperty(
+              key,
+              value['callback'](d, i, c.style.getPropertyValue(key))(t)
+                  .toString(),
+              value['priority']));
         });
 
         _attrMap[c] = tweenList;
         _durationMap[c] = _duration(d, i, c);
         _timerMap[new AnimationTimer(_tick, delay: _delay(d, i, c))] = c;
 
-        if(!_transitionMap.containsKey(c)) {
+        if (!_transitionMap.containsKey(c)) {
           _transitionMap[c] = 1;
         } else {
           _transitionMap[c]++;
@@ -127,8 +129,8 @@
 
     var interpolator = createStringInterpolator(style, newValue.toString());
 
-    return (t) => element.style.setProperty(styleName,
-        interpolator(t).toString(), priority);
+    return (t) => element.style
+        .setProperty(styleName, interpolator(t).toString(), priority);
   }
 
   // Ticks of the transition, this is the callback registered to the
@@ -149,7 +151,7 @@
         activeNode.remove();
       }
 
-      if(_transitionMap[activeNode] > 1) {
+      if (_transitionMap[activeNode] > 1) {
         _transitionMap[activeNode]--;
       } else {
         _transitionMap.remove(activeNode);
@@ -185,7 +187,8 @@
   Transition transition() {
     var e = _selection.first;
     var delay = _delay(_selection.scope.datum(e), 0, e) +
-        _duration(_selection.scope.datum(e), 0, e) + _timerDelay;
+        _duration(_selection.scope.datum(e), 0, e) +
+        _timerDelay;
     var t = new _TransitionImpl(_selection, delay);
     t.ease = ease;
     t.durationWithCallback(_duration);
diff --git a/packages/charted/lib/selection/transition.dart b/packages/charted/lib/selection/transition.dart
index d0c6be2..0f54c0c 100644
--- a/packages/charted/lib/selection/transition.dart
+++ b/packages/charted/lib/selection/transition.dart
@@ -7,7 +7,7 @@
  */
 library charted.selection.transition;
 
-import "dart:html" show Element,document;
+import "dart:html" show Element, document;
 import "package:charted/core/timer.dart";
 import "package:charted/selection/selection.dart";
 import "package:charted/core/interpolators.dart";
@@ -25,7 +25,6 @@
  * Transitions have a default duration of 250ms.
  */
 abstract class Transition {
-
   /** A settable default easing type */
   static EasingFunction defaultEasingType = easeCubic();
 
@@ -108,8 +107,8 @@
    * The function's return value is then used to transition each element's
    * style property.
    */
-  void styleWithCallback(String property,
-      SelectionCallback<String> fn, [String priority]);
+  void styleWithCallback(String property, SelectionCallback<String> fn,
+      [String priority]);
 
   /**
    * Transitions the value of the CSS style property with the specified name
diff --git a/packages/charted/lib/svg/axis.dart b/packages/charted/lib/svg/axis.dart
index 81fc756..474b436 100644
--- a/packages/charted/lib/svg/axis.dart
+++ b/packages/charted/lib/svg/axis.dart
@@ -43,17 +43,17 @@
   /// Formatter for the tick labels
   FormatFunction _tickFormat;
 
-  SvgAxis({
-      this.orientation: ORIENTATION_BOTTOM,
+  SvgAxis(
+      {this.orientation: ORIENTATION_BOTTOM,
       this.innerTickSize: 6,
       this.outerTickSize: 6,
       this.tickPadding: 3,
       Iterable tickValues,
       FormatFunction tickFormat,
-      Scale scale }) : scale = scale == null ? new LinearScale() : scale {
-    _tickFormat = tickFormat == null
-        ? this.scale.createTickFormatter()
-        : tickFormat;
+      Scale scale})
+      : scale = scale == null ? new LinearScale() : scale {
+    _tickFormat =
+        tickFormat == null ? this.scale.createTickFormatter() : tickFormat;
     _tickValues = isNullOrEmpty(tickValues) ? this.scale.ticks : tickValues;
   }
 
@@ -63,13 +63,12 @@
 
   /// Draw an axis on each non-null element in selection
   draw(Selection g, {SvgAxisTicks axisTicksBuilder, bool isRTL: false}) =>
-      g.each((d, i, e) => create(
-          e, g.scope, axisTicksBuilder: axisTicksBuilder, isRTL: isRTL));
+      g.each((d, i, e) =>
+          create(e, g.scope, axisTicksBuilder: axisTicksBuilder, isRTL: isRTL));
 
   /// Create an axis on [element].
-  create(Element element, SelectionScope scope, {
-      SvgAxisTicks axisTicksBuilder, bool isRTL: false}) {
-
+  create(Element element, SelectionScope scope,
+      {SvgAxisTicks axisTicksBuilder, bool isRTL: false}) {
     var group = scope.selectElements([element]),
         older = _scales[element],
         current = _scales[element] = scale.clone(),
@@ -101,10 +100,10 @@
     var enter = ticks.enter.appendWithCallback((d, i, e) {
       var group = Namespace.createChildElement('g', e)
         ..attributes['class'] = 'tick'
-        ..append(Namespace.createChildElement('line',  e))
+        ..append(Namespace.createChildElement('line', e))
         ..append(Namespace.createChildElement('text', e)
-            ..attributes['dy'] =
-                isVertical ? '0.32em' : (isBottom ? '0.71em' : '0'));
+          ..attributes['dy'] =
+              isVertical ? '0.32em' : (isBottom ? '0.71em' : '0'));
       if (!isInitialRender) {
         group.style.setProperty('opacity', EPSILON.toString());
       }
@@ -183,7 +182,7 @@
         range = current.rangeExtent;
     if (path == null) {
       path = Namespace.createChildElement('path', element)
-          ..setAttribute('class', 'domain');
+        ..setAttribute('class', 'domain');
     }
     path.attributes['d'] = isLeft || isRight
         ? 'M${tickSize},${range.min}H0V${range.max}H${tickSize}'
diff --git a/packages/charted/lib/svg/shapes/arc.dart b/packages/charted/lib/svg/shapes/arc.dart
index 78797b1..6e2a396 100644
--- a/packages/charted/lib/svg/shapes/arc.dart
+++ b/packages/charted/lib/svg/shapes/arc.dart
@@ -36,12 +36,11 @@
   /// and element in the context.
   final SelectionCallback<num> endAngleCallback;
 
-  SvgArc({
-      this.innerRadiusCallback : defaultInnerRadiusCallback,
+  SvgArc(
+      {this.innerRadiusCallback: defaultInnerRadiusCallback,
       this.outerRadiusCallback: defaultOuterRadiusCallback,
       this.startAngleCallback: defaultStartAngleCallback,
-      this.endAngleCallback: defaultEndAngleCallback
-  });
+      this.endAngleCallback: defaultEndAngleCallback});
 
   String path(d, int i, Element e) {
     var ir = innerRadiusCallback(d, i, e),
@@ -54,8 +53,13 @@
 
     if (delta > _MAX) {
       return ir > 0
-          ? "M0,$or" "A$or,$or 0 1,1 0,-$or" "A$or,$or 0 1,1 0,$or"
-            "M0,$ir" "A$ir,$ir 0 1,0 0,-$ir" "A$ir,$ir 0 1,0 0,$ir" "Z"
+          ? "M0,$or"
+              "A$or,$or 0 1,1 0,-$or"
+              "A$or,$or 0 1,1 0,$or"
+              "M0,$ir"
+              "A$ir,$ir 0 1,0 0,-$ir"
+              "A$ir,$ir 0 1,0 0,$ir"
+              "Z"
           : "M0,$or" "A$or,$or 0 1,1 0,-$or" "A$or,$or 0 1,1 0,$or" "Z";
     }
 
@@ -66,11 +70,15 @@
         df = delta < PI ? 0 : 1;
 
     return ir > 0
-        ? "M${or * cs},${or * ss}" "A$or,$or 0 $df,1 ${or * ce},${or * se}"
-          "L${ir * ce},${ir * se}" "A$ir,$ir 0 $df,0 ${ir * cs},${ir * ss}"
-          "Z"
-        : "M${or * cs},${or * ss}" "A$or,$or 0 $df,1 ${or * ce},${or * se}"
-          "L0,0" "Z";
+        ? "M${or * cs},${or * ss}"
+            "A$or,$or 0 $df,1 ${or * ce},${or * se}"
+            "L${ir * ce},${ir * se}"
+            "A$ir,$ir 0 $df,0 ${ir * cs},${ir * ss}"
+            "Z"
+        : "M${or * cs},${or * ss}"
+        "A$or,$or 0 $df,1 ${or * ce},${or * se}"
+        "L0,0"
+        "Z";
   }
 
   List centroid(d, int i, Element e) {
@@ -106,12 +114,10 @@
   num startAngle;
   num endAngle;
 
-  SvgArcData(this.data, this.value,
-      this.startAngle, this.endAngle, [
-      this.innerRadius = 0, this.outerRadius = 100 ]);
+  SvgArcData(this.data, this.value, this.startAngle, this.endAngle,
+      [this.innerRadius = 0, this.outerRadius = 100]);
 }
 
-
 /// Returns the interpolator between two [SvgArcData] [a] and [b].
 ///
 /// The interpolator will interpolate the older innerRadius and outerRadius with
@@ -126,6 +132,6 @@
       bi = b.innerRadius - ai,
       bo = b.outerRadius - ao;
 
-  return (t) => new SvgArcData(b.data, b.value,
-    (ast + bst * t), (aen + ben * t), (ai + bi * t), (ao + bo * t));
+  return (t) => new SvgArcData(b.data, b.value, (ast + bst * t),
+      (aen + ben * t), (ai + bi * t), (ao + bo * t));
 }
diff --git a/packages/charted/lib/svg/shapes/line.dart b/packages/charted/lib/svg/shapes/line.dart
index 8b663ec..7e0f6ac 100644
--- a/packages/charted/lib/svg/shapes/line.dart
+++ b/packages/charted/lib/svg/shapes/line.dart
@@ -18,9 +18,7 @@
 class SvgLine implements SvgShape {
   static const LINE_INTERPOLATOR_LINEAR = 'linear';
 
-  static final LINE_INTERPOLATORS = {
-    LINE_INTERPOLATOR_LINEAR: _linear
-  };
+  static final LINE_INTERPOLATORS = {LINE_INTERPOLATOR_LINEAR: _linear};
 
   /// Callback to access/convert datum to x coordinate value.
   final SelectionValueAccessor<num> xValueAccessor;
@@ -39,12 +37,12 @@
   /// Tension of the line, as used by a few interpolators.
   final int tension;
 
-  SvgLine({
-      this.xValueAccessor: defaultDataToX,
+  SvgLine(
+      {this.xValueAccessor: defaultDataToX,
       this.yValueAccessor: defaultDataToY,
       this.isDefined: defaultIsDefined,
       this.tension: 0,
-      String interpolate: LINE_INTERPOLATOR_LINEAR })
+      String interpolate: LINE_INTERPOLATOR_LINEAR})
       : interpolator = LINE_INTERPOLATORS[interpolate] {
     assert(interpolator != null);
   }
@@ -53,13 +51,12 @@
   @override
   String path(data, int index, Element e) {
     assert(data is Iterable);
-    var segments = new StringBuffer(),
-        points = [];
+    var segments = new StringBuffer(), points = [];
     for (int i = 0, len = data.length; i < len; ++i) {
       final d = data.elementAt(i);
       if (isDefined(d, i, e)) {
         points.add(new math.Point(xValueAccessor(d, i), yValueAccessor(d, i)));
-      } else if (points.isNotEmpty){
+      } else if (points.isNotEmpty) {
         segments.write('M${interpolator(points, tension)}');
         points.clear();
       }
diff --git a/packages/charted/lib/svg/shapes/rect.dart b/packages/charted/lib/svg/shapes/rect.dart
index 554efbf..cd89cad 100644
--- a/packages/charted/lib/svg/shapes/rect.dart
+++ b/packages/charted/lib/svg/shapes/rect.dart
@@ -11,17 +11,17 @@
 /// Draw a rectangle at [x], [y] which is [width] pixels wide and
 /// [height] pixels height.  [topLeft], [topRight], [bottomRight] and
 /// [bottomLeft] are the corner radius at each of the four corners.
-String roundedRect(int x, int y, int width, int height,
-    int topLeft, int topRight, int bottomRight, int bottomLeft) =>
-        'M${x+topLeft},${y} '
-        'L${x+width-topRight},${y} '
-            'Q${x+width},${y} ${x+width},${y+topRight}'
-        'L${x+width},${y+height-bottomRight} '
-            'Q${x+width},${y+height} ${x+width-bottomRight},${y+height}'
-        'L${x+bottomLeft},${y+height} '
-            'Q${x},${y+height} ${x},${y+height-bottomLeft}'
-        'L${x},${y+topLeft} '
-            'Q${x},${y} ${x+topLeft},${y} Z';
+String roundedRect(int x, int y, int width, int height, int topLeft,
+        int topRight, int bottomRight, int bottomLeft) =>
+    'M${x+topLeft},${y} '
+    'L${x+width-topRight},${y} '
+    'Q${x+width},${y} ${x+width},${y+topRight}'
+    'L${x+width},${y+height-bottomRight} '
+    'Q${x+width},${y+height} ${x+width-bottomRight},${y+height}'
+    'L${x+bottomLeft},${y+height} '
+    'Q${x},${y+height} ${x},${y+height-bottomLeft}'
+    'L${x},${y+topLeft} '
+    'Q${x},${y} ${x+topLeft},${y} Z';
 
 /// Draw a rectangle with rounded corners on both corners on the right.
 String rightRoundedRect(int x, int y, int width, int height, int radius) {
diff --git a/packages/charted/pubspec.yaml b/packages/charted/pubspec.yaml
index a15a2e3..5dc5abc 100644
--- a/packages/charted/pubspec.yaml
+++ b/packages/charted/pubspec.yaml
@@ -1,5 +1,5 @@
 name: charted
-version: 0.2.9
+version: 0.3.0
 authors:
 - Prasad Sunkari <prsd@google.com>
 - Michael Cheng <midoringo@google.com>
diff --git a/packages/code_transformers/.travis.yml b/packages/code_transformers/.travis.yml
new file mode 100644
index 0000000..7012012
--- /dev/null
+++ b/packages/code_transformers/.travis.yml
@@ -0,0 +1,8 @@
+language: dart
+sudo: false
+dart:
+  - dev
+  - stable
+cache:
+  directories:
+    - $HOME/.pub-cache/hosted
diff --git a/packages/code_transformers/CHANGELOG.md b/packages/code_transformers/CHANGELOG.md
index 5bc681c..2e397c7 100644
--- a/packages/code_transformers/CHANGELOG.md
+++ b/packages/code_transformers/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.2.11
+
+* Revert `0.2.10` release, will be re-released as `0.3.0` since it is actually
+  a breaking change.
+
+## 0.2.10
+
+* Update to use the `test` package instead of the `unittest` package.
+
 ## 0.2.9+4
 
 * Republish 0.2.9+2 under new version.
diff --git a/packages/code_transformers/pubspec.yaml b/packages/code_transformers/pubspec.yaml
index 705aad4..67da04e 100644
--- a/packages/code_transformers/pubspec.yaml
+++ b/packages/code_transformers/pubspec.yaml
@@ -1,5 +1,5 @@
 name: code_transformers
-version: 0.2.9+4
+version: 0.2.11
 author: Dart Team <misc@dartlang.org>
 description: Collection of utilities related to creating barback transformers.
 homepage: https://github.com/dart-lang/code-transformers
@@ -12,5 +12,4 @@
   path: '>=0.9.0 <2.0.0'
   source_maps: '>=0.9.4 <0.11.0'
   source_span: '>=1.0.0 <2.0.0'
-dev_dependencies:
   unittest: '>=0.10.1 <0.12.0'
diff --git a/packages/collection/CHANGELOG.md b/packages/collection/CHANGELOG.md
index ad50fa1..a39a2b5 100644
--- a/packages/collection/CHANGELOG.md
+++ b/packages/collection/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.2.0
+
+* Add string comparators that ignore ASCII case and sort numbers numerically.
+
 ## 1.1.3
 
 * Fix type inconsistencies with `Map` and `Set`.
diff --git a/packages/collection/README.md b/packages/collection/README.md
index 73429a5..8772e65 100644
--- a/packages/collection/README.md
+++ b/packages/collection/README.md
@@ -1,6 +1,4 @@
-#Helper libraries for working with collections.
-
-The `collection` package contains a number of separate libraries
+Contains a number libraries
 with utility functions and classes that makes working with collections easier.
 
 ## Using
@@ -8,15 +6,19 @@
 The `collection` package can be imported as separate libraries, or
 in totality:
 
-    import 'package:collection/algorithms.dart';
-    import 'package:collection/equality.dart';
-    import 'package:collection/iterable_zip.dart';
-    import 'package:collection/priority_queue.dart';
-    import 'package:collection/wrappers.dart';
+```dart
+import 'package:collection/algorithms.dart';
+import 'package:collection/equality.dart';
+import 'package:collection/iterable_zip.dart';
+import 'package:collection/priority_queue.dart';
+import 'package:collection/wrappers.dart';
+```
 
 or
 
-    import 'package:collection/collection.dart';
+```dart
+import 'package:collection/collection.dart';
+```
 
 ## Algorithms
 
@@ -41,7 +43,9 @@
 The library provides ways to define equalities on `Iterable`s, `List`s, `Set`s,
 and `Map`s, as well as combinations of these, such as:
 
-    const MapEquality(const IdentityEquality(), const ListEquality());
+```dart
+const MapEquality(const IdentityEquality(), const ListEquality());
+```
 
 This equality considers maps equal if they have identical keys, and the
 corresponding values are lists with equal (`operator==`) values.
@@ -54,7 +58,7 @@
 
 ## Priority Queue
 
-An interface and implemention of a priority queue.
+An interface and implementation of a priority queue.
 
 
 ## Wrappers
diff --git a/packages/collection/lib/collection.dart b/packages/collection/lib/collection.dart
index 45d3867..6d451b8 100644
--- a/packages/collection/lib/collection.dart
+++ b/packages/collection/lib/collection.dart
@@ -22,5 +22,6 @@
 export "iterable_zip.dart";
 export "priority_queue.dart";
 export "src/canonicalized_map.dart";
+export "src/comparators.dart";
 export "src/queue_list.dart";
 export "wrappers.dart";
diff --git a/packages/collection/lib/equality.dart b/packages/collection/lib/equality.dart
index c6fdafa..5911863 100644
--- a/packages/collection/lib/equality.dart
+++ b/packages/collection/lib/equality.dart
@@ -357,7 +357,7 @@
  *
  * In ordered mode, lists and iterables are required to have equal elements
  * in the same order. In unordered mode, the order of elements in iterables
- * and lists are not importan.
+ * and lists are not important.
  *
  * A list is only equal to another list, likewise for sets and maps. All other
  * iterables are compared as iterables only.
diff --git a/packages/collection/lib/priority_queue.dart b/packages/collection/lib/priority_queue.dart
index efb3239..e1a0177 100644
--- a/packages/collection/lib/priority_queue.dart
+++ b/packages/collection/lib/priority_queue.dart
@@ -275,7 +275,7 @@
    */
   int _locate(E object) {
     if (_length == 0) return -1;
-    // Count positions from one instad of zero. This gives the numbers
+    // Count positions from one instead of zero. This gives the numbers
     // some nice properties. For example, all right children are odd,
     // their left sibling is even, and the parent is found by shifting
     // right by one.
diff --git a/packages/collection/lib/src/comparators.dart b/packages/collection/lib/src/comparators.dart
new file mode 100644
index 0000000..05615ba
--- /dev/null
+++ b/packages/collection/lib/src/comparators.dart
@@ -0,0 +1,399 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file

+// for details. All rights reserved. Use of this source code is governed by a

+// BSD-style license that can be found in the LICENSE file.

+

+library dart.pkg.collection.comparators;

+

+// Character constants.

+const int _zero         = 0x30;

+const int _upperCaseA   = 0x41;

+const int _upperCaseZ   = 0x5a;

+const int _lowerCaseA   = 0x61;

+const int _lowerCaseZ   = 0x7a;

+const int _asciiCaseBit = 0x20;

+

+/// Checks if strings [a] and [b] differ only on the case of ASCII letters.

+///

+/// Strings are equal if they have the same length, and the characters at

+/// each index are the same, or they are ASCII letters where one is upper-case

+/// and the other is the lower-case version of the same letter.

+///

+/// The comparison does not ignore the case of non-ASCII letters, so

+/// an upper-case ae-ligature (Æ) is different from

+/// a lower case ae-ligature (æ).

+///

+/// Ignoring non-ASCII letters is not generally a good idea, but it makes sense

+/// for situations where the strings are known to be ASCII. Examples could

+/// be Dart identifiers, base-64 or hex encoded strings, GUIDs or similar

+/// strings with a known structure.

+bool equalsIgnoreAsciiCase(String a, String b) {

+  if (a.length != b.length) return false;

+  for (int i = 0; i < a.length; i++) {

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar == bChar) continue;

+    // Quick-check for whether this may be different cases of the same letter.

+    if (aChar ^ bChar != _asciiCaseBit) return false;

+    // If it's possible, then check if either character is actually an ASCII

+    // letter.

+    int aCharUpperCase = aChar | _asciiCaseBit;

+    if (_upperCaseA <= aCharUpperCase && aCharUpperCase <= _upperCaseZ) {

+      continue;

+    }

+    return false;

+  }

+  return true;

+}

+

+

+/// Hash code for a string which is compatible with [equalsIgnoreAsciiCase].

+///

+/// The hash code is unaffected by changing the case of ASCII letters, but

+/// the case of non-ASCII letters do affect the result.

+int hashIgnoreAsciiCase(String string) {

+  // Jenkins hash code ( http://en.wikipedia.org/wiki/Jenkins_hash_function).

+  // adapted to smi values.

+  // Same hash used by dart2js for strings, modified to ignore ASCII letter

+  // case.

+  int hash = 0;

+  for (int i = 0; i < string.length; i++) {

+    int char = string.codeUnitAt(i);

+    // Convert lower-case ASCII letters to upper case.upper

+    // This ensures that strings that differ only in case will have the

+    // same hash code.

+    if (_lowerCaseA <= char && char <= _lowerCaseZ) char -= _asciiCaseBit;

+    hash = 0x1fffffff & (hash + char);

+    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));

+    hash >>= 6;

+  }

+  hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));

+  hash >>= 11;

+  return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));

+}

+

+

+/// Compares [a] and [b] lexically, converting ASCII letters to upper case.

+///

+/// Comparison treats all lower-case ASCII letters as upper-case letters,

+/// but does no case conversion for non-ASCII letters.

+///

+/// If two strings differ only on the case of ASCII letters, the one with the

+/// capital letter at the first difference will compare as less than the other

+/// string. This tie-breaking ensures that the comparison is a total ordering

+/// on strings and is compatible with equality.

+///

+/// Ignoring non-ASCII letters is not generally a good idea, but it makes sense

+/// for situations where the strings are known to be ASCII. Examples could

+/// be Dart identifiers, base-64 or hex encoded strings, GUIDs or similar

+/// strings with a known structure.

+int compareAsciiUpperCase(String a, String b) {

+  int defaultResult = 0; // Returned if no difference found.

+  for (int i = 0; i < a.length; i++) {

+    if (i >= b.length) return 1;

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar == bChar) continue;

+    // Upper-case if letters.

+    int aUpperCase = aChar;

+    int bUpperCase = bChar;

+    if (_lowerCaseA <= aChar && aChar <= _lowerCaseZ) {

+      aUpperCase -= _asciiCaseBit;

+    }

+    if (_lowerCaseA <= bChar && bChar <= _lowerCaseZ) {

+      bUpperCase -= _asciiCaseBit;

+    }

+    if (aUpperCase != bUpperCase) return (aUpperCase - bUpperCase).sign;

+    if (defaultResult == 0) defaultResult = (aChar - bChar);

+  }

+  if (b.length > a.length) return -1;

+  return defaultResult.sign;

+}

+

+

+/// Compares [a] and [b] lexically, converting ASCII letters to lower case.

+///

+/// Comparison treats all upper-case ASCII letters as lower-case letters,

+/// but does no case conversion for non-ASCII letters.

+///

+/// If two strings differ only on the case of ASCII letters, the one with the

+/// capital letter at the first difference will compare as less than the other

+/// string. This tie-breaking ensures that the comparison is a total ordering

+/// on strings.

+///

+/// Ignoring non-ASCII letters is not generally a good idea, but it makes sense

+/// for situations where the strings are known to be ASCII. Examples could

+/// be Dart identifiers, base-64 or hex encoded strings, GUIDs or similar

+/// strings with a known structure.

+int compareAsciiLowerCase(String a, String b) {

+  int defaultResult = 0;

+  for (int i = 0; i < a.length; i++) {

+    if (i >= b.length) return 1;

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar == bChar) continue;

+    int aLowerCase = aChar;

+    int bLowerCase = bChar;

+    // Upper case if ASCII letters.

+    if (_upperCaseA <= bChar && bChar <= _upperCaseZ) {

+      bLowerCase += _asciiCaseBit;

+    }

+    if (_upperCaseA <= aChar && aChar <= _upperCaseZ) {

+      aLowerCase += _asciiCaseBit;

+    }

+    if (aLowerCase != bLowerCase) return (aLowerCase - bLowerCase).sign;

+    if (defaultResult == 0) defaultResult = aChar - bChar;

+  }

+  if (b.length > a.length) return -1;

+  return defaultResult.sign;

+}

+

+/// Compares strings [a] and [b] according to [natural sort ordering].

+///

+/// A natural sort ordering is a lexical ordering where embedded

+/// numerals (digit sequences) are treated as a single unit and ordered by

+/// numerical value.

+/// This means that `"a10b"` will be ordered after `"a7b"` in natural

+/// ordering, where lexical ordering would put the `1` before the `7`, ignoring

+/// that the `1` is part of a larger number.

+///

+/// Example:

+/// The following strings are in the order they would be sorted by using this

+/// comparison function:

+///

+///     "a", "a0", "a0b", "a1", "a01", "a9", "a10", "a100", "a100b", "aa"

+///

+/// [natural sort ordering]: https://en.wikipedia.org/wiki/Natural_sort_order

+int compareNatural(String a, String b) {

+  for (int i = 0; i < a.length; i++) {

+    if (i >= b.length) return 1;

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar != bChar) {

+      return _compareNaturally(a, b, i, aChar, bChar);

+    }

+  }

+  if (b.length > a.length) return -1;

+  return 0;

+}

+

+/// Compares strings [a] and [b] according to lower-case

+/// [natural sort ordering].

+///

+/// ASCII letters are converted to lower case before being compared, like

+/// for [compareAsciiLowerCase], then the result is compared like for

+/// [compareNatural].

+///

+/// If two strings differ only on the case of ASCII letters, the one with the

+/// capital letter at the first difference will compare as less than the other

+/// string. This tie-breaking ensures that the comparison is a total ordering

+/// on strings.

+///

+/// [natural sort ordering]: https://en.wikipedia.org/wiki/Natural_sort_order

+int compareAsciiLowerCaseNatural(String a, String b) {

+  int defaultResult = 0; // Returned if no difference found.

+  for (int i = 0; i < a.length; i++) {

+    if (i >= b.length) return 1;

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar == bChar) continue;

+    int aLowerCase = aChar;

+    int bLowerCase = bChar;

+    if (_upperCaseA <= aChar && aChar <= _upperCaseZ) {

+      aLowerCase += _asciiCaseBit;

+    }

+    if (_upperCaseA <= bChar && bChar <= _upperCaseZ) {

+      bLowerCase += _asciiCaseBit;

+    }

+    if (aLowerCase != bLowerCase) {

+      return _compareNaturally(a, b, i, aLowerCase, bLowerCase);

+    }

+    if (defaultResult == 0) defaultResult = aChar - bChar;

+  }

+  if (b.length > a.length) return -1;

+  return defaultResult.sign;

+}

+

+/// Compares strings [a] and [b] according to upper-case

+/// [natural sort ordering].

+///

+/// ASCII letters are converted to upper case before being compared, like

+/// for [compareAsciiUpperCase], then the result is compared like for

+/// [compareNatural].

+///

+/// If two strings differ only on the case of ASCII letters, the one with the

+/// capital letter at the first difference will compare as less than the other

+/// string. This tie-breaking ensures that the comparison is a total ordering

+/// on strings

+///

+/// [natural sort ordering]: https://en.wikipedia.org/wiki/Natural_sort_order

+int compareAsciiUpperCaseNatural(String a, String b) {

+  int defaultResult = 0;

+  for (int i = 0; i < a.length; i++) {

+    if (i >= b.length) return 1;

+    var aChar = a.codeUnitAt(i);

+    var bChar = b.codeUnitAt(i);

+    if (aChar == bChar) continue;

+    int aUpperCase = aChar;

+    int bUpperCase = bChar;

+    if (_lowerCaseA <= aChar && aChar <= _lowerCaseZ) {

+      aUpperCase -= _asciiCaseBit;

+    }

+    if (_lowerCaseA <= bChar && bChar <= _lowerCaseZ) {

+      bUpperCase -= _asciiCaseBit;

+    }

+    if (aUpperCase != bUpperCase) {

+      return _compareNaturally(a, b, i, aUpperCase, bUpperCase);

+    }

+    if (defaultResult == 0) defaultResult = aChar - bChar;

+  }

+  if (b.length > a.length) return -1;

+  return defaultResult.sign;

+}

+

+/// Check for numbers overlapping the current mismatched characters.

+///

+/// If both [aChar] and [bChar] are digits, use numerical comparison.

+/// Check if the previous characters is a non-zero number, and if not,

+/// skip - but count - leading zeros before comparing numbers.

+///

+/// If one is a digit and the other isn't, check if the previous character

+/// is a digit, and if so, the the one with the digit is the greater number.

+///

+/// Otherwise just returns the difference between [aChar] and [bChar].

+int _compareNaturally(

+    String a, String b, int index, int aChar, int bChar) {

+  assert(aChar != bChar);

+  var aIsDigit = _isDigit(aChar);

+  var bIsDigit = _isDigit(bChar);

+  if (aIsDigit) {

+    if (bIsDigit) {

+      return _compareNumerically(a, b, aChar, bChar, index);

+    } else if (index > 0 && _isDigit(a.codeUnitAt(index - 1))) {

+      // aChar is the continuation of a longer number.

+      return 1;

+    }

+  } else if (bIsDigit && index > 0 && _isDigit(b.codeUnitAt(index - 1))) {

+    // bChar is the continuation of a longer number.

+    return -1;

+  }

+  // Characters are both non-digits, or not continuation of earlier number.

+  return (aChar - bChar).sign;

+}

+

+/// Compare numbers overlapping [aChar] and [bChar] numerically.

+///

+/// If the numbers have the same numerical value, but one has more leading

+/// zeros, the longer number is considered greater than the shorter one.

+///

+/// This ensures a total ordering on strings compatible with equality.

+int _compareNumerically(String a, String b, int aChar, int bChar, int index) {

+  // Both are digits. Find the first significant different digit, then find

+  // the length of the numbers.

+  if (_isNonZeroNumberSuffix(a, index)) {

+    // Part of a longer number, differs at this index, just count the length.

+    int result = _compareDigitCount(a, b, index, index);

+    if (result != 0) return result;

+    // If same length, the current character is the most significant differing

+    // digit.

+    return (aChar - bChar).sign;

+  }

+  // Not part of larger (non-zero) number, so skip leading zeros before

+  // comparing numbers.

+  int aIndex = index;

+  int bIndex = index;

+  if (aChar == _zero) {

+    do {

+      aIndex++;

+      if (aIndex == a.length) return -1;  // number in a is zero, b is not.

+      aChar = a.codeUnitAt(aIndex);

+    } while (aChar == _zero);

+    if (!_isDigit(aChar)) return -1;

+  } else if (bChar == _zero) {

+    do {

+      bIndex++;

+      if (bIndex == b.length) return 1;  // number in b is zero, a is not.

+      bChar = b.codeUnitAt(bIndex);

+    } while (bChar == _zero);

+    if (!_isDigit(bChar)) return 1;

+  }

+  if (aChar != bChar) {

+    int result = _compareDigitCount(a, b, aIndex, bIndex);

+    if (result != 0) return result;

+    return (aChar - bChar).sign;

+  }

+  // Same leading digit, one had more leading zeros.

+  // Compare digits until reaching a difference.

+  while (true) {

+    var aIsDigit = false;

+    var bIsDigit = false;

+    aChar = 0;

+    bChar = 0;

+    if (++aIndex < a.length) {

+      aChar = a.codeUnitAt(aIndex);

+      aIsDigit = _isDigit(aChar);

+    }

+    if (++bIndex < b.length) {

+      bChar = b.codeUnitAt(bIndex);

+      bIsDigit = _isDigit(bChar);

+    }

+    if (aIsDigit) {

+      if (bIsDigit) {

+        if (aChar == bChar) continue;

+        // First different digit found.

+        break;

+      }

+      // bChar is non-digit, so a has longer number.

+      return 1;

+    } else if (bIsDigit) {

+      return -1;  // b has longer number.

+    } else {

+      // Neither is digit, so numbers had same numerical value.

+      // Fall back on number of leading zeros

+      // (reflected by difference in indices).

+      return (aIndex - bIndex).sign;

+    }

+  }

+  // At first differing digits.

+  int result = _compareDigitCount(a, b, aIndex, bIndex);

+  if (result != 0) return result;

+  return (aChar - bChar).sign;

+}

+

+/// Checks which of [a] and [b] has the longest sequence of digits.

+///

+/// Starts counting from `i + 1` and `j + 1` (assumes that `a[i]` and `b[j]` are

+/// both already known to be digits).

+int _compareDigitCount(String a, String b, int i, int j) {

+  while (++i < a.length) {

+    bool aIsDigit = _isDigit(a.codeUnitAt(i));

+    if (++j == b.length) return aIsDigit ? 1 : 0;

+    bool bIsDigit = _isDigit(b.codeUnitAt(j));

+    if (aIsDigit) {

+      if (bIsDigit) continue;

+      return 1;

+    } else if (bIsDigit) {

+      return -1;

+    } else {

+      return 0;

+    }

+  }

+  if (++j < b.length && _isDigit(b.codeUnitAt(j))) {

+    return -1;

+  }

+  return 0;

+}

+

+bool _isDigit(int charCode) => (charCode ^ _zero) <= 9;

+

+/// Check if the digit at [index] is continuing a non-zero number.

+///

+/// If there is no non-zero digits before, then leading zeros at [index]

+/// are also ignored when comparing numerically. If there is a non-zero digit

+/// before, then zeros at [index] are significant.

+bool _isNonZeroNumberSuffix(String string, int index) {

+  while (--index >= 0) {

+    int char = string.codeUnitAt(index);

+    if (char != _zero) return _isDigit(char);

+  }

+  return false;

+}

diff --git a/packages/collection/lib/wrappers.dart b/packages/collection/lib/wrappers.dart
index 9f8b833..30c736e 100644
--- a/packages/collection/lib/wrappers.dart
+++ b/packages/collection/lib/wrappers.dart
@@ -6,8 +6,8 @@
  * Delegating wrappers for [Iterable], [List], [Set], [Queue] and [Map].
  *
  * Also adds unmodifiable views for `Set` and `Map`, and a fixed length
- * view for `List`. The unmodifable list view from `dart:collection` is exported
- * as well, just for completeness.
+ * view for `List`. The unmodifiable list view from `dart:collection` is
+ * exported as well, just for completeness.
  */
 library dart.pkg.collection.wrappers;
 
diff --git a/packages/collection/pubspec.yaml b/packages/collection/pubspec.yaml
index 514ec4b..3642321 100644
--- a/packages/collection/pubspec.yaml
+++ b/packages/collection/pubspec.yaml
@@ -1,5 +1,5 @@
 name: collection
-version: 1.1.3
+version: 1.2.0
 author: Dart Team <misc@dartlang.org>
 description: Collections and utilities functions and classes related to collections.
 homepage: https://www.github.com/dart-lang/collection
diff --git a/packages/collection/test/comparators_test.dart b/packages/collection/test/comparators_test.dart
new file mode 100644
index 0000000..4acdc2c
--- /dev/null
+++ b/packages/collection/test/comparators_test.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:collection/collection.dart";
+import "package:test/test.dart";
+
+void main() {
+  List<String> strings = [
+    "",
+    "\x00",
+    " ",
+    "+",
+    "/",
+    "0",
+    "00",
+    "000",
+    "001",
+    "01",
+    "011",
+    "1",
+    "100",
+    "11",
+    "110",
+    "9",
+    ":",
+    "=",
+    "@",
+    "A",
+    "A0",
+    "A000A",
+    "A001A",
+    "A00A",
+    "A01A",
+    "A0A",
+    "A1A",
+    "AA",
+    "AAB",
+    "AB",
+    "Z",
+    "[",
+    "_",
+    "`",
+    "a",
+    "a0",
+    "a000a",
+    "a001a",
+    "a00a",
+    "a01a",
+    "a0a",
+    "a1a",
+    "aa",
+    "aab",
+    "ab",
+    "z",
+    "{",
+    "~"
+  ];
+
+  sortedBy(compare) => strings.toList()..shuffle()..sort(compare);
+
+  test("String.compareTo", () {
+    expect(sortedBy(null), strings);
+  });
+  test("compareAsciiLowerCase", () {
+    expect(sortedBy(compareAsciiLowerCase),
+           sortedBy((a, b) {
+             int delta = a.toLowerCase().compareTo(b.toLowerCase());
+             if (delta != 0) return delta;
+             if (a == b) return 0;
+             return a.compareTo(b);
+           }));
+  });
+  test("compareAsciiUpperCase", () {
+    expect(sortedBy(compareAsciiUpperCase),
+           sortedBy((a, b) {
+             int delta = a.toUpperCase().compareTo(b.toUpperCase());
+             if (delta != 0) return delta;
+             if (a == b) return 0;
+             return a.compareTo(b);
+           }));
+  });
+
+  // Replace any digit sequence by ("0", value, length) as char codes.
+  // This will sort alphabetically (by charcode) the way digits sort
+  // numerically, and the leading 0 means it sorts like a digit
+  // compared to non-digits.
+  replaceNumbers(string) => string.replaceAllMapped(new RegExp(r"\d+"), (m) {
+    var digits = m[0];
+    return new String.fromCharCodes([0x30, int.parse(digits), digits.length]);
+  });
+
+  test("compareNatural", () {
+    expect(sortedBy(compareNatural),
+           sortedBy((a, b) => replaceNumbers(a).compareTo(replaceNumbers(b))));
+  });
+
+  test("compareAsciiLowerCaseNatural", () {
+    expect(sortedBy(compareAsciiLowerCaseNatural),
+           sortedBy((a, b) {
+             int delta = replaceNumbers(a.toLowerCase()).compareTo(
+                             replaceNumbers(b.toLowerCase()));
+             if (delta != 0) return delta;
+             if (a == b) return 0;
+             return a.compareTo(b);
+           }));
+  });
+
+  test("compareAsciiUpperCaseNatural", () {
+    expect(sortedBy(compareAsciiUpperCaseNatural),
+           sortedBy((a, b) {
+             int delta = replaceNumbers(a.toUpperCase()).compareTo(
+                             replaceNumbers(b.toUpperCase()));
+             if (delta != 0) return delta;
+             if (a == b) return 0;
+             return a.compareTo(b);
+           }));
+  });
+}
diff --git a/packages/collection/test/wrapper_test.dart b/packages/collection/test/wrapper_test.dart
index a3526a3..e3043a2 100644
--- a/packages/collection/test/wrapper_test.dart
+++ b/packages/collection/test/wrapper_test.dart
@@ -147,7 +147,7 @@
     expect.first.equals.first;
     // Default values of the Iterable interface will be added in the
     // second call to firstWhere, so we must record them in our
-    // expectation (which doesn't have the interface implementat or
+    // expectation (which doesn't have the interface implemented or
     // its default values).
     expect.firstWhere(func1, orElse: null).equals.firstWhere(func1);
     expect.firstWhere(func1, orElse: func0).equals.
diff --git a/packages/csslib/.classpath b/packages/csslib/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/packages/csslib/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/packages/csslib/.gitignore b/packages/csslib/.gitignore
index 388eff0..a6867f2 100644
--- a/packages/csslib/.gitignore
+++ b/packages/csslib/.gitignore
@@ -1,8 +1,8 @@
 # Don’t commit the following directories created by pub.
-.buildlog
 .pub/
 build/
 packages
+.packages
 
 # Or the files created by dart2js.
 *.dart.js
@@ -11,4 +11,4 @@
 *.js.map
 
 # Include when developing application packages.
-pubspec.lock
\ No newline at end of file
+pubspec.lock
diff --git a/packages/csslib/.packages b/packages/csslib/.packages
deleted file mode 100644
index 7c47ae3..0000000
--- a/packages/csslib/.packages
+++ /dev/null
@@ -1,37 +0,0 @@
-# Generate by pub on 2015-07-10 14:34:54.820.
-# This file contains a map from Dart package names to Dart package locations.
-# Dart tools, including the Dart VM and Dart analyzer, rely on the content.
-# AUTO GENERATED - DO NOT EDIT
-analyzer:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/analyzer-0.25.1/lib/
-args:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/args-0.13.2/lib/
-async:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/async-1.2.0/lib/
-barback:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/barback-0.15.2+4/lib/
-browser:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/browser-0.10.0+2/lib/
-charcode:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.0/lib/
-collection:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/collection-1.1.1/lib/
-crypto:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/crypto-0.9.0/lib/
-csslib:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/csslib-0.12.1/lib/
-glob:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/glob-1.0.4/lib/
-html:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/html-0.12.1+2/lib/
-http_multi_server:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/http_multi_server-1.3.2/lib/
-http_parser:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/http_parser-0.0.2+7/lib/
-logging:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/logging-0.11.1/lib/
-matcher:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.0+1/lib/
-mime:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/mime-0.9.3/lib/
-package_config:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/package_config-0.1.1/lib/
-path:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/path-1.3.6/lib/
-plugin:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/plugin-0.1.0/lib/
-pool:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/pool-1.1.0/lib/
-pub_semver:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.2.1/lib/
-shelf:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/shelf-0.6.2/lib/
-shelf_static:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.2/lib/
-shelf_web_socket:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.0.1+2/lib/
-source_map_stack_trace:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.0.4/lib/
-source_maps:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.1/lib/
-source_span:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/source_span-1.1.2/lib/
-stack_trace:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.3.4/lib/
-string_scanner:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/string_scanner-0.1.3+1/lib/
-test:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/test-0.12.3+6/lib/
-utf:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+2/lib/
-watcher:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.6/lib/
-yaml:file:///usr/local/google/home/sigmund/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.3/lib/
diff --git a/packages/csslib/.project b/packages/csslib/.project
new file mode 100644
index 0000000..081cd0c
--- /dev/null
+++ b/packages/csslib/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>csslib</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/packages/csslib/.status b/packages/csslib/.status
deleted file mode 100644
index e9f2b00..0000000
--- a/packages/csslib/.status
+++ /dev/null
@@ -1,3 +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.
diff --git a/packages/csslib/.test_config b/packages/csslib/.test_config
new file mode 100644
index 0000000..412fc5c
--- /dev/null
+++ b/packages/csslib/.test_config
@@ -0,0 +1,3 @@
+{
+  "test_package": true
+}
\ No newline at end of file
diff --git a/packages/csslib/CHANGELOG.md b/packages/csslib/CHANGELOG.md
index 4d14f0b..b4ee9e1 100644
--- a/packages/csslib/CHANGELOG.md
+++ b/packages/csslib/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.12.2
+
+ * Fix to handle calc functions however, the expressions are treated as a
+   LiteralTerm and not fully parsed into the AST.
+
 ## 0.12.1
 
  * Fix to handling of escapes in strings.
diff --git a/packages/csslib/README.md b/packages/csslib/README.md
index e64fd9b..1610d3b 100644
--- a/packages/csslib/README.md
+++ b/packages/csslib/README.md
@@ -1,20 +1,12 @@
-csslib in Pure Dart
-===================
+CSS parser library for Dart
+==========================
 
-This is a pure [Dart][dart] [CSS parser][cssparse]. Since it's 100%
-Dart you can use it safely from a script or server side app.
+This is a [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) parser written entirely in [Dart][dart].
+It can be used in the client/server/command line.
 
-Installation
-------------
-
-Add this to your `pubspec.yaml` (or create it):
-```yaml
-dependencies:
-  csslib: any
-```
-Then run the [Pub Package Manager][pub] (comes with the Dart SDK):
-
-    pub install
+This package is installed with [Pub][pub], see:
+[install instructions](https://pub.dartlang.org/packages/csslib#installing)
+for this package.
 
 Usage
 -----
@@ -34,48 +26,18 @@
 You can pass a String or list of bytes to `parse`.
 
 
-Updating
---------
-
-You can upgrade the library with:
-
-    pub update
-
-Disclaimer: the APIs are not finished. Updating may break your code. If that
-happens, you can check the
-[commit log](https://github.com/dart-lang/csslib/commits/master), to figure
-out what the change was.
-
-If you want to avoid breakage, you can also put the version constraint in your
-`pubspec.yaml` in place of the word `any`.
-
 Running Tests
 -------------
 
-All tests (both canary and suite) should be passing.  Canary are quick test
-verifies that basic CSS is working.  The suite tests are a comprehensive set of
-~11,000 tests.
-
+Basic tests can be found in this repository:
 ```bash
-export DART_SDK=path/to/dart/sdk
-
-# Make sure dependencies are installed
-pub install
-
-# Run command both canary and the suite tests
-test/run.sh
+pub run test
 ```
 
-  Run only the canary test:
-
+The full CSS test suite can be found in https://github.com/dart-lang/csslib-test-suite
 ```bash
- test/run.sh canary
-```
-
-  Run only the suite tests:
-
-```bash
- test/run.sh suite
+cd ../csslib-test-suite
+./run.sh
 ```
 
 [dart]: http://www.dartlang.org/
diff --git a/packages/csslib/lib/parser.dart b/packages/csslib/lib/parser.dart
index 8692693..b3a22d6 100644
--- a/packages/csslib/lib/parser.dart
+++ b/packages/csslib/lib/parser.dart
@@ -64,7 +64,7 @@
   analyze([tree], errors: errors, options: options);
 
   if (polyfill) {
-    var processCss = new PolyFill(messages, true);
+    var processCss = new PolyFill(messages);
     processCss.process(tree, includes: includes);
   }
 
@@ -430,6 +430,7 @@
     if (unaryOp != -1 || type != null || exprs.length > 0) {
       return new MediaQuery(unaryOp, type, exprs, _makeSpan(start));
     }
+    return null;
   }
 
   MediaExpression processMediaExpression([bool andOperator = false]) {
@@ -453,9 +454,9 @@
         }
       } else if (isChecked) {
         _warning("Missing media feature in media expression", _makeSpan(start));
-        return null;
       }
     }
+    return null;
   }
 
   /**
@@ -798,7 +799,6 @@
     _eat(TokenKind.LBRACE);
 
     List<TreeNode> productions = [];
-    List<TreeNode> declarations = [];
     var mixinDirective;
 
     var start = _peekToken.span;
@@ -984,6 +984,7 @@
       return new RuleSet(
           selectorGroup, processDeclarations(), selectorGroup.span);
     }
+    return null;
   }
 
   /**
@@ -1191,6 +1192,7 @@
     if (selectors.length > 0) {
       return new SelectorGroup(selectors, _makeSpan(start));
     }
+    return null;
   }
 
   /**
@@ -1602,6 +1604,7 @@
 
       return new AttributeSelector(attrName, op, value, _makeSpan(start));
     }
+    return null;
   }
 
   //  Declaration grammar:
@@ -1763,6 +1766,7 @@
     if (styleType != null) {
       return buildDartStyleNode(styleType, exprs, dartStyles);
     }
+    return null;
   }
 
   FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) {
@@ -1910,10 +1914,8 @@
           return processOneNumber(exprs, styleType);
         }
         break;
-      default:
-        // Don't handle it.
-        return null;
     }
+    return null;
   }
 
   // TODO(terry): Look at handling width of thin, thick, etc. any none numbers
@@ -1956,6 +1958,7 @@
           return new PaddingExpression(exprs.span, bottom: value);
       }
     }
+    return null;
   }
 
   /**
@@ -2185,6 +2188,8 @@
         var nameValue = identifier(); // Snarf up the ident we'll remap, maybe.
 
         if (!ieFilter && _maybeEat(TokenKind.LPAREN)) {
+          var calc = processCalc(nameValue);
+          if (calc != null) return calc;
           // FUNCTION
           return processFunction(nameValue);
         }
@@ -2439,6 +2444,64 @@
     }
   }
 
+  //  TODO(terry): Hack to gobble up the calc expression as a string looking
+  //               for the matching RPAREN the expression is not parsed into the
+  //               AST.
+  //
+  //  grammar should be:
+  //
+  //    <calc()> = calc( <calc-sum> )
+  //    <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]*
+  //    <calc-product> = <calc-value> [ '*' <calc-value> | '/' <number> ]*
+  //    <calc-value> = <number> | <dimension> | <percentage> | ( <calc-sum> )
+  //
+  String processCalcExpression() {
+    var inString = tokenizer._inString;
+    tokenizer._inString = false;
+
+    // Gobble up everything until we hit our stop token.
+    var stringValue = new StringBuffer();
+    var left = 1;
+    var matchingParens = false;
+    while (_peek() != TokenKind.END_OF_FILE && !matchingParens) {
+      var token = _peek();
+      if (token == TokenKind.LPAREN)
+        left++;
+      else if (token == TokenKind.RPAREN)
+        left--;
+
+      matchingParens = left == 0;
+      if (!matchingParens) stringValue.write(_next().text);
+    }
+
+    if (!matchingParens) {
+      _error("problem parsing function expected ), ", _peekToken.span);
+    }
+
+    tokenizer._inString = inString;
+
+    return stringValue.toString();
+  }
+
+  CalcTerm processCalc(Identifier func) {
+    var start = _peekToken.span;
+
+    var name = func.name;
+    if (name == 'calc') {
+      // TODO(terry): Implement expression parsing properly.
+      String expression = processCalcExpression();
+      var calcExpr = new LiteralTerm(expression, expression, _makeSpan(start));
+
+      if (!_maybeEat(TokenKind.RPAREN)) {
+        _error("problem parsing function expected ), ", _peekToken.span);
+      }
+
+      return new CalcTerm(name, name, calcExpr, _makeSpan(start));
+    }
+
+    return null;
+  }
+
   //  Function grammar:
   //
   //  function:     IDENT '(' expr ')'
@@ -2463,9 +2526,6 @@
         }
 
         return new UriTerm(urlParam, _makeSpan(start));
-      case 'calc':
-        // TODO(terry): Implement expression handling...
-        break;
       case 'var':
         // TODO(terry): Consider handling var in IE specific filter/progid.  This
         //              will require parsing entire IE specific syntax e.g.,
diff --git a/packages/csslib/lib/src/analyzer.dart b/packages/csslib/lib/src/analyzer.dart
index 4fdd833..fc27ceb 100644
--- a/packages/csslib/lib/src/analyzer.dart
+++ b/packages/csslib/lib/src/analyzer.dart
@@ -463,8 +463,8 @@
       } else if (currDef is MixinRulesetDirective && _anyRulesets(currDef)) {
         // currDef is MixinRulesetDirective
         MixinRulesetDirective mixinRuleset = currDef;
-        int index = mixinRuleset.rulesets.indexOf(node as dynamic);
-        mixinRuleset.rulesets.replaceRange(index, index + 1, [new NoOp()]);
+        int index = mixinRuleset.rulesets.indexOf(node);
+        mixinRuleset.rulesets.removeAt(index);
         _messages.warning(
             'Using declaration mixin ${node.name} as top-level mixin',
             node.span);
@@ -472,13 +472,12 @@
     } else {
       if (currDef is MixinRulesetDirective) {
         MixinRulesetDirective rulesetDirect = currDef as MixinRulesetDirective;
-        var index = 0;
-        rulesetDirect.rulesets.forEach((entry) {
+        rulesetDirect.rulesets.removeWhere((entry) {
           if (entry == node) {
-            rulesetDirect.rulesets.replaceRange(index, index + 1, [new NoOp()]);
             _messages.warning('Undefined mixin ${node.name}', node.span);
+            return true;
           }
-          index++;
+          return false;
         });
       }
     }
diff --git a/packages/csslib/lib/src/css_printer.dart b/packages/csslib/lib/src/css_printer.dart
index 125b5ae..a62ca47 100644
--- a/packages/csslib/lib/src/css_printer.dart
+++ b/packages/csslib/lib/src/css_printer.dart
@@ -38,6 +38,12 @@
   //              flag for obfuscation.
   bool get _isTesting => !prettyPrint;
 
+  void visitCalcTerm(CalcTerm node) {
+    emit('${node.text}(');
+    node.expr.visit(this);
+    emit(')');
+  }
+
   void visitCssComment(CssComment node) {
     emit('/* ${node.comment} */');
   }
diff --git a/packages/csslib/lib/src/polyfill.dart b/packages/csslib/lib/src/polyfill.dart
index 9b682ce..b18abd1 100644
--- a/packages/csslib/lib/src/polyfill.dart
+++ b/packages/csslib/lib/src/polyfill.dart
@@ -10,7 +10,6 @@
  */
 class PolyFill {
   final Messages _messages;
-  final bool _warningsAsErrors;
   Map<String, VarDefinition> _allVarDefinitions =
       new Map<String, VarDefinition>();
 
@@ -21,7 +20,7 @@
    * CSS pseudo-elements 'name::custom-element' is mapped to the manged name
    * associated with the pseudo-element key.
    */
-  PolyFill(this._messages, this._warningsAsErrors);
+  PolyFill(this._messages);
 
   /**
    * Run the analyzer on every file that is a style sheet or any component that
@@ -227,7 +226,7 @@
   var expressions = varDef.expression as Expressions;
   for (var expr in expressions.expressions) {
     if (expr is VarUsage) {
-      var usageName = (expr as VarUsage).name;
+      var usageName = expr.name;
       var foundDef = varDefs[usageName];
 
       // If foundDef is unknown check if defaultValues; if it exist then resolve
@@ -236,7 +235,7 @@
         // We're either a VarUsage or terminal definition if in varDefs;
         // either way replace VarUsage with it's default value because the
         // VarDefinition isn't found.
-        var defaultValues = (expr as VarUsage).defaultValues;
+        var defaultValues = expr.defaultValues;
         var replaceExprs = expressions.expressions;
         assert(replaceExprs.length == 1);
         replaceExprs.replaceRange(0, 1, defaultValues);
diff --git a/packages/csslib/lib/src/property.dart b/packages/csslib/lib/src/property.dart
index 5d6dc14..c2cf776 100644
--- a/packages/csslib/lib/src/property.dart
+++ b/packages/csslib/lib/src/property.dart
@@ -278,10 +278,11 @@
           return new Hsla(args[0], args[1], args[2], args[3]).toHexArgbString();
         default:
           // Type not defined UnsupportedOperationException should have thrown.
-          assert(true);
+          assert(false);
           break;
       }
     }
+    return null;
   }
 
   static int hexToInt(String hex) => int.parse(hex, radix: 16);
@@ -785,6 +786,7 @@
 
   String get cssExpression {
     // TODO(terry): TBD
+    return null;
   }
 }
 
diff --git a/packages/csslib/lib/src/tokenkind.dart b/packages/csslib/lib/src/tokenkind.dart
index 617f062..27ccb4b 100644
--- a/packages/csslib/lib/src/tokenkind.dart
+++ b/packages/csslib/lib/src/tokenkind.dart
@@ -192,7 +192,7 @@
   static const int PSEUDO_CLASS_NAME = 705; // :pseudoClass
   static const int NEGATION = 706; // NOT
 
-  static const List<Map<int, String>> _DIRECTIVES = const [
+  static const List<Map<String, dynamic>> _DIRECTIVES = const [
     const {'type': TokenKind.DIRECTIVE_IMPORT, 'value': 'import'},
     const {'type': TokenKind.DIRECTIVE_MEDIA, 'value': 'media'},
     const {'type': TokenKind.DIRECTIVE_PAGE, 'value': 'page'},
@@ -218,13 +218,13 @@
     const {'type': TokenKind.DIRECTIVE_EXTEND, 'value': 'extend'},
   ];
 
-  static const List<Map<int, String>> MEDIA_OPERATORS = const [
+  static const List<Map<String, dynamic>> MEDIA_OPERATORS = const [
     const {'type': TokenKind.MEDIA_OP_ONLY, 'value': 'only'},
     const {'type': TokenKind.MEDIA_OP_NOT, 'value': 'not'},
     const {'type': TokenKind.MEDIA_OP_AND, 'value': 'and'},
   ];
 
-  static const List<Map<int, String>> MARGIN_DIRECTIVES = const [
+  static const List<Map<String, dynamic>> MARGIN_DIRECTIVES = const [
     const {
       'type': TokenKind.MARGIN_DIRECTIVE_TOPLEFTCORNER,
       'value': 'top-left-corner'
diff --git a/packages/csslib/lib/src/tree.dart b/packages/csslib/lib/src/tree.dart
index 5dad435..ba8370e 100644
--- a/packages/csslib/lib/src/tree.dart
+++ b/packages/csslib/lib/src/tree.dart
@@ -44,6 +44,21 @@
   String get name => 'not';
 }
 
+// calc(...)
+// TODO(terry): Hack to handle calc however the expressions should be fully
+//              parsed and in the AST.
+class CalcTerm extends LiteralTerm {
+  final LiteralTerm expr;
+
+  CalcTerm(var value, String t, this.expr, SourceSpan span)
+      : super(value, t, span);
+
+  CalcTerm clone() => new CalcTerm(value, text, expr.clone(), span);
+  visit(VisitorBase visitor) => visitor.visitCalcTerm(this);
+
+  String toString() => "$text($expr)";
+}
+
 // /*  ....   */
 class CssComment extends TreeNode {
   final String comment;
@@ -197,6 +212,7 @@
       case TokenKind.NO_MATCH:
         return '';
     }
+    return null;
   }
 
   // Return the TokenKind for operator used by visitAttributeSelector.
@@ -215,6 +231,7 @@
       case TokenKind.SUBSTRING_MATCH:
         return 'SUBSTRING_MATCH';
     }
+    return null;
   }
 
   String valueToString() {
@@ -572,6 +589,7 @@
       case TokenKind.DIRECTIVE_O_KEYFRAMES:
         return '@-o-keyframes';
     }
+    return null;
   }
 
   KeyFrameDirective clone() {
@@ -676,7 +694,7 @@
 
 /** Support a Sass @mixin. See http://sass-lang.com for description. */
 class MixinRulesetDirective extends MixinDefinition {
-  final List<RuleSet> rulesets;
+  final List rulesets;
 
   MixinRulesetDirective(String name, List<VarDefinitionDirective> args,
       bool varArgs, this.rulesets, SourceSpan span)
diff --git a/packages/csslib/lib/src/tree_printer.dart b/packages/csslib/lib/src/tree_printer.dart
index 030a868..9b0a6c2 100644
--- a/packages/csslib/lib/src/tree_printer.dart
+++ b/packages/csslib/lib/src/tree_printer.dart
@@ -46,6 +46,13 @@
     heading('Directive', node);
   }
 
+  void visitCalcTerm(CalcTerm node) {
+    heading('CalcTerm', node);
+    output.depth++;
+    super.visitCalcTerm(node);
+    output.depth--;
+  }
+
   void visitCssComment(CssComment node) {
     heading('Comment', node);
     output.depth++;
diff --git a/packages/csslib/lib/src/validate.dart b/packages/csslib/lib/src/validate.dart
index d45cd95..e716e66 100644
--- a/packages/csslib/lib/src/validate.dart
+++ b/packages/csslib/lib/src/validate.dart
@@ -53,7 +53,6 @@
   // Validate the @{css expression} only .class and #elementId are valid inside
   // of @{...}.
   static template(List<Selector> selectors) {
-    var errorSelector; // signal which selector didn't match.
     bool found = false; // signal if a selector is matched.
     int matches = 0; // < 0 IdSelectors, > 0 ClassSelector
 
diff --git a/packages/csslib/lib/visitor.dart b/packages/csslib/lib/visitor.dart
index fa0f8d2..b6babbd 100644
--- a/packages/csslib/lib/visitor.dart
+++ b/packages/csslib/lib/visitor.dart
@@ -13,99 +13,100 @@
 part 'src/tree_printer.dart';
 
 abstract class VisitorBase {
-  void visitCssComment(CssComment node);
-  void visitCommentDefinition(CommentDefinition node);
-  void visitStyleSheet(StyleSheet node);
-  void visitNoOp(NoOp node);
-  void visitTopLevelProduction(TopLevelProduction node);
-  void visitDirective(Directive node);
-  void visitMediaExpression(MediaExpression node);
-  void visitMediaQuery(MediaQuery node);
-  void visitMediaDirective(MediaDirective node);
-  void visitHostDirective(HostDirective node);
-  void visitPageDirective(PageDirective node);
-  void visitCharsetDirective(CharsetDirective node);
-  void visitImportDirective(ImportDirective node);
-  void visitKeyFrameDirective(KeyFrameDirective node);
-  void visitKeyFrameBlock(KeyFrameBlock node);
-  void visitFontFaceDirective(FontFaceDirective node);
-  void visitStyletDirective(StyletDirective node);
-  void visitNamespaceDirective(NamespaceDirective node);
-  void visitVarDefinitionDirective(VarDefinitionDirective node);
-  void visitMixinDefinition(MixinDefinition node);
-  void visitMixinRulesetDirective(MixinRulesetDirective node);
-  void visitMixinDeclarationDirective(MixinDeclarationDirective node);
-  void visitIncludeDirective(IncludeDirective node);
-  void visitContentDirective(ContentDirective node);
+  visitCalcTerm(CalcTerm node);
+  visitCssComment(CssComment node);
+  visitCommentDefinition(CommentDefinition node);
+  visitStyleSheet(StyleSheet node);
+  visitNoOp(NoOp node);
+  visitTopLevelProduction(TopLevelProduction node);
+  visitDirective(Directive node);
+  visitMediaExpression(MediaExpression node);
+  visitMediaQuery(MediaQuery node);
+  visitMediaDirective(MediaDirective node);
+  visitHostDirective(HostDirective node);
+  visitPageDirective(PageDirective node);
+  visitCharsetDirective(CharsetDirective node);
+  visitImportDirective(ImportDirective node);
+  visitKeyFrameDirective(KeyFrameDirective node);
+  visitKeyFrameBlock(KeyFrameBlock node);
+  visitFontFaceDirective(FontFaceDirective node);
+  visitStyletDirective(StyletDirective node);
+  visitNamespaceDirective(NamespaceDirective node);
+  visitVarDefinitionDirective(VarDefinitionDirective node);
+  visitMixinDefinition(MixinDefinition node);
+  visitMixinRulesetDirective(MixinRulesetDirective node);
+  visitMixinDeclarationDirective(MixinDeclarationDirective node);
+  visitIncludeDirective(IncludeDirective node);
+  visitContentDirective(ContentDirective node);
 
-  void visitRuleSet(RuleSet node);
-  void visitDeclarationGroup(DeclarationGroup node);
-  void visitMarginGroup(MarginGroup node);
-  void visitDeclaration(Declaration node);
-  void visitVarDefinition(VarDefinition node);
-  void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node);
-  void visitExtendDeclaration(ExtendDeclaration node);
-  void visitSelectorGroup(SelectorGroup node);
-  void visitSelector(Selector node);
-  void visitSimpleSelectorSequence(SimpleSelectorSequence node);
-  void visitSimpleSelector(SimpleSelector node);
-  void visitElementSelector(ElementSelector node);
-  void visitNamespaceSelector(NamespaceSelector node);
-  void visitAttributeSelector(AttributeSelector node);
-  void visitIdSelector(IdSelector node);
-  void visitClassSelector(ClassSelector node);
-  void visitPseudoClassSelector(PseudoClassSelector node);
-  void visitPseudoElementSelector(PseudoElementSelector node);
-  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node);
-  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node);
-  void visitNegationSelector(NegationSelector node);
-  void visitSelectorExpression(SelectorExpression node);
+  visitRuleSet(RuleSet node);
+  visitDeclarationGroup(DeclarationGroup node);
+  visitMarginGroup(MarginGroup node);
+  visitDeclaration(Declaration node);
+  visitVarDefinition(VarDefinition node);
+  visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node);
+  visitExtendDeclaration(ExtendDeclaration node);
+  visitSelectorGroup(SelectorGroup node);
+  visitSelector(Selector node);
+  visitSimpleSelectorSequence(SimpleSelectorSequence node);
+  visitSimpleSelector(SimpleSelector node);
+  visitElementSelector(ElementSelector node);
+  visitNamespaceSelector(NamespaceSelector node);
+  visitAttributeSelector(AttributeSelector node);
+  visitIdSelector(IdSelector node);
+  visitClassSelector(ClassSelector node);
+  visitPseudoClassSelector(PseudoClassSelector node);
+  visitPseudoElementSelector(PseudoElementSelector node);
+  visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node);
+  visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node);
+  visitNegationSelector(NegationSelector node);
+  visitSelectorExpression(SelectorExpression node);
 
-  void visitUnicodeRangeTerm(UnicodeRangeTerm node);
-  void visitLiteralTerm(LiteralTerm node);
-  void visitHexColorTerm(HexColorTerm node);
-  void visitNumberTerm(NumberTerm node);
-  void visitUnitTerm(UnitTerm node);
-  void visitLengthTerm(LengthTerm node);
-  void visitPercentageTerm(PercentageTerm node);
-  void visitEmTerm(EmTerm node);
-  void visitExTerm(ExTerm node);
-  void visitAngleTerm(AngleTerm node);
-  void visitTimeTerm(TimeTerm node);
-  void visitFreqTerm(FreqTerm node);
-  void visitFractionTerm(FractionTerm node);
-  void visitUriTerm(UriTerm node);
-  void visitResolutionTerm(ResolutionTerm node);
-  void visitChTerm(ChTerm node);
-  void visitRemTerm(RemTerm node);
-  void visitViewportTerm(ViewportTerm node);
-  void visitFunctionTerm(FunctionTerm node);
-  void visitGroupTerm(GroupTerm node);
-  void visitItemTerm(ItemTerm node);
-  void visitIE8Term(IE8Term node);
-  void visitOperatorSlash(OperatorSlash node);
-  void visitOperatorComma(OperatorComma node);
-  void visitOperatorPlus(OperatorPlus node);
-  void visitOperatorMinus(OperatorMinus node);
-  void visitVarUsage(VarUsage node);
+  visitUnicodeRangeTerm(UnicodeRangeTerm node);
+  visitLiteralTerm(LiteralTerm node);
+  visitHexColorTerm(HexColorTerm node);
+  visitNumberTerm(NumberTerm node);
+  visitUnitTerm(UnitTerm node);
+  visitLengthTerm(LengthTerm node);
+  visitPercentageTerm(PercentageTerm node);
+  visitEmTerm(EmTerm node);
+  visitExTerm(ExTerm node);
+  visitAngleTerm(AngleTerm node);
+  visitTimeTerm(TimeTerm node);
+  visitFreqTerm(FreqTerm node);
+  visitFractionTerm(FractionTerm node);
+  visitUriTerm(UriTerm node);
+  visitResolutionTerm(ResolutionTerm node);
+  visitChTerm(ChTerm node);
+  visitRemTerm(RemTerm node);
+  visitViewportTerm(ViewportTerm node);
+  visitFunctionTerm(FunctionTerm node);
+  visitGroupTerm(GroupTerm node);
+  visitItemTerm(ItemTerm node);
+  visitIE8Term(IE8Term node);
+  visitOperatorSlash(OperatorSlash node);
+  visitOperatorComma(OperatorComma node);
+  visitOperatorPlus(OperatorPlus node);
+  visitOperatorMinus(OperatorMinus node);
+  visitVarUsage(VarUsage node);
 
-  void visitExpressions(Expressions node);
-  void visitBinaryExpression(BinaryExpression node);
-  void visitUnaryExpression(UnaryExpression node);
+  visitExpressions(Expressions node);
+  visitBinaryExpression(BinaryExpression node);
+  visitUnaryExpression(UnaryExpression node);
 
-  void visitIdentifier(Identifier node);
-  void visitWildcard(Wildcard node);
-  void visitThisOperator(ThisOperator node);
-  void visitNegation(Negation node);
+  visitIdentifier(Identifier node);
+  visitWildcard(Wildcard node);
+  visitThisOperator(ThisOperator node);
+  visitNegation(Negation node);
 
-  void visitDartStyleExpression(DartStyleExpression node);
-  void visitFontExpression(FontExpression node);
-  void visitBoxExpression(BoxExpression node);
-  void visitMarginExpression(MarginExpression node);
-  void visitBorderExpression(BorderExpression node);
-  void visitHeightExpression(HeightExpression node);
-  void visitPaddingExpression(PaddingExpression node);
-  void visitWidthExpression(WidthExpression node);
+  visitDartStyleExpression(DartStyleExpression node);
+  visitFontExpression(FontExpression node);
+  visitBoxExpression(BoxExpression node);
+  visitMarginExpression(MarginExpression node);
+  visitBorderExpression(BorderExpression node);
+  visitHeightExpression(HeightExpression node);
+  visitPaddingExpression(PaddingExpression node);
+  visitWidthExpression(WidthExpression node);
 }
 
 /** Base vistor class for the style sheet AST. */
@@ -120,33 +121,38 @@
     }
   }
 
-  void visitTree(StyleSheet tree) => visitStyleSheet(tree);
+  visitTree(StyleSheet tree) => visitStyleSheet(tree);
 
-  void visitStyleSheet(StyleSheet ss) {
+  visitStyleSheet(StyleSheet ss) {
     _visitNodeList(ss.topLevels);
   }
 
-  void visitNoOp(NoOp node) {}
+  visitNoOp(NoOp node) {}
 
-  void visitTopLevelProduction(TopLevelProduction node) {}
+  visitTopLevelProduction(TopLevelProduction node) {}
 
-  void visitDirective(Directive node) {}
+  visitDirective(Directive node) {}
 
-  void visitCssComment(CssComment node) {}
+  visitCalcTerm(CalcTerm node) {
+    visitLiteralTerm(node);
+    visitLiteralTerm(node.expr);
+  }
 
-  void visitCommentDefinition(CommentDefinition node) {}
+  visitCssComment(CssComment node) {}
 
-  void visitMediaExpression(MediaExpression node) {
+  visitCommentDefinition(CommentDefinition node) {}
+
+  visitMediaExpression(MediaExpression node) {
     visitExpressions(node.exprs);
   }
 
-  void visitMediaQuery(MediaQuery node) {
+  visitMediaQuery(MediaQuery node) {
     for (var mediaExpr in node.expressions) {
       visitMediaExpression(mediaExpr);
     }
   }
 
-  void visitMediaDirective(MediaDirective node) {
+  visitMediaDirective(MediaDirective node) {
     for (var mediaQuery in node.mediaQueries) {
       visitMediaQuery(mediaQuery);
     }
@@ -155,13 +161,13 @@
     }
   }
 
-  void visitHostDirective(HostDirective node) {
+  visitHostDirective(HostDirective node) {
     for (var ruleset in node.rulesets) {
       visitRuleSet(ruleset);
     }
   }
 
-  void visitPageDirective(PageDirective node) {
+  visitPageDirective(PageDirective node) {
     for (var declGroup in node._declsMargin) {
       if (declGroup is MarginGroup) {
         visitMarginGroup(declGroup);
@@ -171,285 +177,285 @@
     }
   }
 
-  void visitCharsetDirective(CharsetDirective node) {}
+  visitCharsetDirective(CharsetDirective node) {}
 
-  void visitImportDirective(ImportDirective node) {
+  visitImportDirective(ImportDirective node) {
     for (var mediaQuery in node.mediaQueries) {
       visitMediaQuery(mediaQuery);
     }
   }
 
-  void visitKeyFrameDirective(KeyFrameDirective node) {
+  visitKeyFrameDirective(KeyFrameDirective node) {
     visitIdentifier(node.name);
     _visitNodeList(node._blocks);
   }
 
-  void visitKeyFrameBlock(KeyFrameBlock node) {
+  visitKeyFrameBlock(KeyFrameBlock node) {
     visitExpressions(node._blockSelectors);
     visitDeclarationGroup(node._declarations);
   }
 
-  void visitFontFaceDirective(FontFaceDirective node) {
+  visitFontFaceDirective(FontFaceDirective node) {
     visitDeclarationGroup(node._declarations);
   }
 
-  void visitStyletDirective(StyletDirective node) {
+  visitStyletDirective(StyletDirective node) {
     _visitNodeList(node.rulesets);
   }
 
-  void visitNamespaceDirective(NamespaceDirective node) {}
+  visitNamespaceDirective(NamespaceDirective node) {}
 
-  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+  visitVarDefinitionDirective(VarDefinitionDirective node) {
     visitVarDefinition(node.def);
   }
 
-  void visitMixinRulesetDirective(MixinRulesetDirective node) {
+  visitMixinRulesetDirective(MixinRulesetDirective node) {
     _visitNodeList(node.rulesets);
   }
 
-  void visitMixinDefinition(MixinDefinition node) {}
+  visitMixinDefinition(MixinDefinition node) {}
 
-  void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+  visitMixinDeclarationDirective(MixinDeclarationDirective node) {
     visitDeclarationGroup(node.declarations);
   }
 
-  void visitIncludeDirective(IncludeDirective node) {
+  visitIncludeDirective(IncludeDirective node) {
     for (var index = 0; index < node.args.length; index++) {
       var param = node.args[index];
       _visitNodeList(param);
     }
   }
 
-  void visitContentDirective(ContentDirective node) {
+  visitContentDirective(ContentDirective node) {
     // TODO(terry): TBD
   }
 
-  void visitRuleSet(RuleSet node) {
+  visitRuleSet(RuleSet node) {
     visitSelectorGroup(node._selectorGroup);
     visitDeclarationGroup(node._declarationGroup);
   }
 
-  void visitDeclarationGroup(DeclarationGroup node) {
+  visitDeclarationGroup(DeclarationGroup node) {
     _visitNodeList(node.declarations);
   }
 
-  void visitMarginGroup(MarginGroup node) => visitDeclarationGroup(node);
+  visitMarginGroup(MarginGroup node) => visitDeclarationGroup(node);
 
-  void visitDeclaration(Declaration node) {
+  visitDeclaration(Declaration node) {
     visitIdentifier(node._property);
     if (node._expression != null) node._expression.visit(this);
   }
 
-  void visitVarDefinition(VarDefinition node) {
+  visitVarDefinition(VarDefinition node) {
     visitIdentifier(node._property);
     if (node._expression != null) node._expression.visit(this);
   }
 
-  void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
+  visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
     visitIncludeDirective(node.include);
   }
 
-  void visitExtendDeclaration(ExtendDeclaration node) {
+  visitExtendDeclaration(ExtendDeclaration node) {
     _visitNodeList(node.selectors);
   }
 
-  void visitSelectorGroup(SelectorGroup node) {
+  visitSelectorGroup(SelectorGroup node) {
     _visitNodeList(node.selectors);
   }
 
-  void visitSelector(Selector node) {
+  visitSelector(Selector node) {
     _visitNodeList(node.simpleSelectorSequences);
   }
 
-  void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+  visitSimpleSelectorSequence(SimpleSelectorSequence node) {
     node.simpleSelector.visit(this);
   }
 
-  void visitSimpleSelector(SimpleSelector node) => node._name.visit(this);
+  visitSimpleSelector(SimpleSelector node) => node._name.visit(this);
 
-  void visitNamespaceSelector(NamespaceSelector node) {
+  visitNamespaceSelector(NamespaceSelector node) {
     if (node._namespace != null) node._namespace.visit(this);
     if (node.nameAsSimpleSelector != null) {
       node.nameAsSimpleSelector.visit(this);
     }
   }
 
-  void visitElementSelector(ElementSelector node) => visitSimpleSelector(node);
+  visitElementSelector(ElementSelector node) => visitSimpleSelector(node);
 
-  void visitAttributeSelector(AttributeSelector node) {
+  visitAttributeSelector(AttributeSelector node) {
     visitSimpleSelector(node);
   }
 
-  void visitIdSelector(IdSelector node) => visitSimpleSelector(node);
+  visitIdSelector(IdSelector node) => visitSimpleSelector(node);
 
-  void visitClassSelector(ClassSelector node) => visitSimpleSelector(node);
+  visitClassSelector(ClassSelector node) => visitSimpleSelector(node);
 
-  void visitPseudoClassSelector(PseudoClassSelector node) =>
+  visitPseudoClassSelector(PseudoClassSelector node) =>
       visitSimpleSelector(node);
 
-  void visitPseudoElementSelector(PseudoElementSelector node) =>
+  visitPseudoElementSelector(PseudoElementSelector node) =>
       visitSimpleSelector(node);
 
-  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) =>
+  visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) =>
       visitSimpleSelector(node);
 
-  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) =>
+  visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) =>
       visitSimpleSelector(node);
 
-  void visitNegationSelector(NegationSelector node) =>
+  visitNegationSelector(NegationSelector node) =>
       visitSimpleSelector(node);
 
-  void visitSelectorExpression(SelectorExpression node) {
+  visitSelectorExpression(SelectorExpression node) {
     _visitNodeList(node.expressions);
   }
 
-  void visitUnicodeRangeTerm(UnicodeRangeTerm node) {}
+  visitUnicodeRangeTerm(UnicodeRangeTerm node) {}
 
-  void visitLiteralTerm(LiteralTerm node) {}
+  visitLiteralTerm(LiteralTerm node) {}
 
-  void visitHexColorTerm(HexColorTerm node) {}
+  visitHexColorTerm(HexColorTerm node) {}
 
-  void visitNumberTerm(NumberTerm node) {}
+  visitNumberTerm(NumberTerm node) {}
 
-  void visitUnitTerm(UnitTerm node) {}
+  visitUnitTerm(UnitTerm node) {}
 
-  void visitLengthTerm(LengthTerm node) {
+  visitLengthTerm(LengthTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitPercentageTerm(PercentageTerm node) {
+  visitPercentageTerm(PercentageTerm node) {
     visitLiteralTerm(node);
   }
 
-  void visitEmTerm(EmTerm node) {
+  visitEmTerm(EmTerm node) {
     visitLiteralTerm(node);
   }
 
-  void visitExTerm(ExTerm node) {
+  visitExTerm(ExTerm node) {
     visitLiteralTerm(node);
   }
 
-  void visitAngleTerm(AngleTerm node) {
+  visitAngleTerm(AngleTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitTimeTerm(TimeTerm node) {
+  visitTimeTerm(TimeTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitFreqTerm(FreqTerm node) {
+  visitFreqTerm(FreqTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitFractionTerm(FractionTerm node) {
+  visitFractionTerm(FractionTerm node) {
     visitLiteralTerm(node);
   }
 
-  void visitUriTerm(UriTerm node) {
+  visitUriTerm(UriTerm node) {
     visitLiteralTerm(node);
   }
 
-  void visitResolutionTerm(ResolutionTerm node) {
+  visitResolutionTerm(ResolutionTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitChTerm(ChTerm node) {
+  visitChTerm(ChTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitRemTerm(RemTerm node) {
+  visitRemTerm(RemTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitViewportTerm(ViewportTerm node) {
+  visitViewportTerm(ViewportTerm node) {
     visitUnitTerm(node);
   }
 
-  void visitFunctionTerm(FunctionTerm node) {
+  visitFunctionTerm(FunctionTerm node) {
     visitLiteralTerm(node);
     visitExpressions(node._params);
   }
 
-  void visitGroupTerm(GroupTerm node) {
+  visitGroupTerm(GroupTerm node) {
     for (var term in node._terms) {
       term.visit(this);
     }
   }
 
-  void visitItemTerm(ItemTerm node) {
+  visitItemTerm(ItemTerm node) {
     visitNumberTerm(node);
   }
 
-  void visitIE8Term(IE8Term node) {}
+  visitIE8Term(IE8Term node) {}
 
-  void visitOperatorSlash(OperatorSlash node) {}
+  visitOperatorSlash(OperatorSlash node) {}
 
-  void visitOperatorComma(OperatorComma node) {}
+  visitOperatorComma(OperatorComma node) {}
 
-  void visitOperatorPlus(OperatorPlus node) {}
+  visitOperatorPlus(OperatorPlus node) {}
 
-  void visitOperatorMinus(OperatorMinus node) {}
+  visitOperatorMinus(OperatorMinus node) {}
 
-  void visitVarUsage(VarUsage node) {
+  visitVarUsage(VarUsage node) {
     _visitNodeList(node.defaultValues);
   }
 
-  void visitExpressions(Expressions node) {
+  visitExpressions(Expressions node) {
     _visitNodeList(node.expressions);
   }
 
-  void visitBinaryExpression(BinaryExpression node) {
+  visitBinaryExpression(BinaryExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitUnaryExpression(UnaryExpression node) {
+  visitUnaryExpression(UnaryExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitIdentifier(Identifier node) {}
+  visitIdentifier(Identifier node) {}
 
-  void visitWildcard(Wildcard node) {}
+  visitWildcard(Wildcard node) {}
 
-  void visitThisOperator(ThisOperator node) {}
+  visitThisOperator(ThisOperator node) {}
 
-  void visitNegation(Negation node) {}
+  visitNegation(Negation node) {}
 
-  void visitDartStyleExpression(DartStyleExpression node) {}
+  visitDartStyleExpression(DartStyleExpression node) {}
 
-  void visitFontExpression(FontExpression node) {
+  visitFontExpression(FontExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitBoxExpression(BoxExpression node) {
+  visitBoxExpression(BoxExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitMarginExpression(MarginExpression node) {
+  visitMarginExpression(MarginExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitBorderExpression(BorderExpression node) {
+  visitBorderExpression(BorderExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitHeightExpression(HeightExpression node) {
+  visitHeightExpression(HeightExpression node) {
     // TODO(terry): TB
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitPaddingExpression(PaddingExpression node) {
+  visitPaddingExpression(PaddingExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 
-  void visitWidthExpression(WidthExpression node) {
+  visitWidthExpression(WidthExpression node) {
     // TODO(terry): TBD
-    throw UnimplementedError;
+    throw new UnimplementedError();
   }
 }
diff --git a/packages/csslib/pubspec.yaml b/packages/csslib/pubspec.yaml
index 70923da..96f403e 100644
--- a/packages/csslib/pubspec.yaml
+++ b/packages/csslib/pubspec.yaml
@@ -1,5 +1,5 @@
 name: csslib
-version: 0.12.1
+version: 0.12.2
 author: Polymer.dart Team <web-ui-dev@dartlang.org>
 description: A library for parsing CSS.
 homepage: https://github.com/dart-lang/csslib
diff --git a/packages/csslib/test/declaration_test.dart b/packages/csslib/test/declaration_test.dart
index 8326a03..de589d7 100644
--- a/packages/csslib/test/declaration_test.dart
+++ b/packages/csslib/test/declaration_test.dart
@@ -1005,6 +1005,62 @@
   expect(errorMessage.span.text.trim(), '');
 }
 
+void testExpressionSpans() {
+  final input = r'''.foo { width: 50px; }''';
+  var stylesheet = parseCss(input);
+  var decl = stylesheet.topLevels.single.declarationGroup.declarations.single;
+  // This passes
+  expect(decl.span.text, 'width: 50px');
+  // This currently fails
+  expect(decl.expression.span.text, '50px');
+}
+
+void simpleCalc() {
+  final input = r'''.foo { height: calc(100% - 55px); }''';
+  var stylesheet = parseCss(input);
+  var decl = stylesheet.topLevels.single.declarationGroup.declarations.single;
+  expect(decl.span.text, 'height: calc(100% - 55px)');
+}
+
+void complexCalc() {
+  final input = r'''.foo { left: calc((100%/3 - 2) * 1em - 2 * 1px); }''';
+  var stylesheet = parseCss(input);
+  var decl = stylesheet.topLevels.single.declarationGroup.declarations.single;
+  expect(decl.span.text, 'left: calc((100%/3 - 2) * 1em - 2 * 1px)');
+}
+
+void twoCalcs() {
+  final input = r'''.foo { margin: calc(1rem - 2px) calc(1rem - 1px); }''';
+  var stylesheet = parseCss(input);
+  var decl = stylesheet.topLevels.single.declarationGroup.declarations.single;
+  expect(decl.span.text, 'margin: calc(1rem - 2px) calc(1rem - 1px)');
+}
+
+void selectorWithCalcs() {
+  var errors = [];
+  final String input = r'''
+.foo {
+  width: calc(1em + 5 * 2em);
+  height: calc(1px + 2%) !important;
+  border: 5px calc(1pt + 2cm) 6px calc(1em + 1in + 2px) red;
+  border: calc(5px + 1em) 0px 1px calc(10 + 20 + 1px);
+  margin: 25px calc(50px + (100% / (3 - 1em) - 20%)) calc(10px + 10 * 20) calc(100% - 10px);
+}''';
+  final String generated = r'''
+.foo {
+  width: calc(1em + 5 * 2em);
+  height: calc(1px + 2%) !important;
+  border: 5px calc(1pt + 2cm) 6px calc(1em + 1in + 2px) #f00;
+  border: calc(5px + 1em) 0px 1px calc(10 + 20 + 1px);
+  margin: 25px calc(50px + (100% / (3 - 1em) - 20%)) calc(10px + 10 * 20) calc(100% - 10px);
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
 main() {
   test('Simple Terms', testSimpleTerms);
   test('Declarations', testDeclarations);
@@ -1021,4 +1077,14 @@
   test('IE stuff', testIE);
   test('IE declaration syntax', testIEDeclaration);
   test('Hanging bugs', testHangs);
+  test('Expression spans', testExpressionSpans,
+      skip: 'expression spans are broken'
+            ' (https://github.com/dart-lang/csslib/issues/15)');
+  group('calc function', () {
+    test('simple calc', simpleCalc);
+    test('single complex', complexCalc);
+    test('two calc terms for same declaration', twoCalcs);
+    test('selector with many calc declarations', selectorWithCalcs);
+  });
 }
+
diff --git a/packages/dart_style/._.status b/packages/dart_style/._.status
deleted file mode 100644
index 4080994..0000000
--- a/packages/dart_style/._.status
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/._AUTHORS b/packages/dart_style/._AUTHORS
deleted file mode 100644
index fa0c94c..0000000
--- a/packages/dart_style/._AUTHORS
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/._LICENSE b/packages/dart_style/._LICENSE
deleted file mode 100644
index 8d50f72..0000000
--- a/packages/dart_style/._LICENSE
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/._PATENTS b/packages/dart_style/._PATENTS
deleted file mode 100644
index 0abd44b..0000000
--- a/packages/dart_style/._PATENTS
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/CHANGELOG.md b/packages/dart_style/CHANGELOG.md
index 731fa32..93ae7dd 100644
--- a/packages/dart_style/CHANGELOG.md
+++ b/packages/dart_style/CHANGELOG.md
@@ -1,3 +1,32 @@
+# 0.2.1
+
+* `--version` command line argument (#240).
+* Split the first `.` in a method chain if the target splits (#255).
+* Don't collapse states that differ by unbound rule constraints (#424).
+* Better handling for functions in method chains (#367, #398).
+* Better handling of large parameter metadata annotations (#387, #444).
+* Smarter splitting around collections in named parameters (#394).
+* Split calls if properties in a chain split (#399).
+* Don't allow splitting inside empty functions (#404).
+* Consider a rule live if it constrains a rule in the overflow line (#407).
+* Allow splitting in prefix expressions (#410).
+* Correctly constrain collections in argument lists (#420, #463, #465).
+* Better indentation of collection literals (#421, #469).
+* Only show a hidden directory once in the output (#428).
+* Allow splitting between type and variable name (#429, #439, #454).
+* Better indentation for binary operators in `=>` bodies (#434.
+* Tweak splitting around assignment (#436, #437).
+* Indent multi-line collections in default values (#441).
+* Don't drop metadata on part directives (#443).
+* Handle `if` statements without curly bodies better (#448).
+* Handle loop statements without curly bodies better (#449).
+* Allow splitting before `get` and `set` (#462).
+* Add `--indent` to specify leading indent (#464).
+* Ensure collection elements line split separately (#474).
+* Allow redirecting constructors to wrap (#475).
+* Handle index expressions in the middle of call chains.
+* Optimize splitting lines with many rules.
+
 # 0.2.0
 
 * Treat functions nested inside function calls like block arguments (#366).
diff --git a/packages/dart_style/README.md b/packages/dart_style/README.md
index 3a7ed96..0594b6e 100644
--- a/packages/dart_style/README.md
+++ b/packages/dart_style/README.md
@@ -1,46 +1,88 @@
 The dart_style package defines an automatic, opinionated formatter for Dart
 code. It replaces the whitespace in your program with what it deems to be the
-best formatting for it. Resulting code should following the [Dart style guide][]
+best formatting for it. Resulting code should follow the [Dart style guide][]
 but, moreso, should look nice to most human readers, most of the time.
 
 [dart style guide]: https://www.dartlang.org/articles/style-guide/
 
-It handles indentation, inline whitespace and (by far the most difficult),
-intelligent line wrapping. It has no problems with nested collections, function
+The formatter handles indentation, inline whitespace and
+(by far the most difficult), intelligent line wrapping.
+It has no problems with nested collections, function
 expressions, long argument lists, or otherwise tricky code.
 
-## Usage
+The formatter turns code like this:
 
-The package exposes a simple command-line wrapper around the core formatting
-library. The easiest way to invoke it is to [globally activate][] the package
-and let pub put its executable on your path:
+```
+// BEFORE formatting
+if (tag=='style'||tag=='script'&&(type==null||type == TYPE_JS
+      ||type==TYPE_DART)||
+  tag=='link'&&(rel=='stylesheet'||rel=='import')) {}
+```
+
+into:
+
+```
+  // AFTER formatting
+  if (tag == 'style' ||
+      tag == 'script' &&
+          (type == null || type == TYPE_JS || type == TYPE_DART) ||
+      tag == 'link' && (rel == 'stylesheet' || rel == 'import')) {}
+```
+
+The formatter will never break your code&mdash;you can safely invoke it
+automatically from build and presubmit scripts.
+
+## Getting dartfmt
+
+Dartfmt is included in the Dart SDK, so you might want to add the SDK's bin
+directory to your system path.
+
+If you want to make sure you are running the latest version of dartfmt,
+you can [globally activate][] the package from the dart_style package
+on pub.dartlang.org, and let pub put its executable on your path:
 
     $ pub global activate dart_style
     $ dartfmt ...
 
 [globally activate]: https://www.dartlang.org/tools/pub/cmd/pub-global.html
 
-If you don't want `dartformat` on your path, you can run it explicitly:
+If you don't want `dartfmt` on your path, you can run it explicitly:
 
     $ pub global activate dart_style --no-executables
     $ pub global run dart_style:format ...
 
-The formatter takes a list of paths, which can point to directories or files.
+## Using dartfmt
+
+IDEs and editors that support Dart usually provide easy ways to run the
+formatter. For example, in WebStorm you can right-click a .dart file
+and then choose **Reformat with Dart Style**.
+
+Here's a simple example of using dartfmt on the command line:
+
+```
+dartfmt test.dart
+```
+
+This command formats the `test.dart` file and writes the result to
+standard output.
+
+Dartfmt takes a list of paths, which can point to directories or files.
 If the path is a directory, it processes every `.dart` file in that directory
 or any of its subdirectories.
+If no file or directory is specified, dartfmt reads from standard input.
 
 By default, it formats each file and just prints the resulting code to stdout.
-If you pass `-w`, it will instead overwrite your existing files with the
+If you pass `-w`, it overwrites your existing files with the
 formatted results.
 
-You may pass a `--line-length` option to control the width of the page that it
+You may pass a `-l` option to control the width of the page that it
 wraps lines to fit within, but you're strongly encouraged to keep the default
 line length of 80 columns.
 
 ### Validating files
 
 If you want to use the formatter in something like a [presubmit script][] or
-[commit hook][], you can use the `--dry-run` option. If you pass that, the
+[commit hook][], you can use the `-n` dry run option. If you specify `-n`, the
 formatter prints the paths of the files whose contents would change if the
 formatter were run normally. If it prints no output, then everything is already
 correctly formatted.
@@ -48,7 +90,7 @@
 [presubmit script]: http://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
 [commit hook]: http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
 
-### Using it programmatically
+## Using the dart_style API
 
 The package also exposes a single dart_style library containing a programmatic
 API for formatting code. Simple usage looks like this:
@@ -71,219 +113,13 @@
       }
     }
 
-## FAQ
+## Other resources
 
-### Why have a formatter?
+* Before sending an email, see if you are asking a
+  [frequently asked question][faq].
 
-The has a few goals, in order of descending priority:
-    
-1.  **Produce consistently formatted code.** Consistent style improves
-    readability because you aren't distracted by variance in style between
-    different parts of a program. It makes it easier to contribute to others'
-    code because their style will already be familiar to you.
-    
-2.  **End debates about style issues in code reviews.** This consumes an
-    astonishingly large quantity of very valuable engineering energy. Style
-    debates are time-consuming, upset people, and rarely change anyone's mind.
-    They make code reviews take longer and be more acromonious.
-    
-3.  **Free users from having to think about and apply formatting.** When
-    writing code, you don't have to try to figure out the best way to split a
-    line and then pain-stakingly add in the line breaks. When you do a global
-    refactor that changes the length of some identifier, you don't have to go
-    back and rewrap all of the lines. When you're in the zone, you can just
-    pump out code and let the formatter tidy it up for you as you go.
-    
-4.  **Produce beautiful, readable output that helps users understand the code.**
-    We could solve all of the above goals with a formatter that just removed
-    *all* whitespace, but that wouldn't be very human-friendly. So, finally,
-    the formatter tries very hard to produce output that is not just consistent
-    but readable to a human. It tries to use indentation and line breaks to
-    highlight the structure and organization of the code.
-    
-    In several cases, the formatter has pointed out bugs where the existing
-    indentation was misleading and didn't represent what the code actually did.
-    For example, automated formatted would have helped make Apple's
-    ["gotofail"][gotofail] security bug easier to notice:
-    
-    ```c
-    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
-        goto fail;
-        goto fail;
-    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
-        goto fail;
-    ```
-    
-    The formatter would change this to:
-    
-    ```c
-    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
-        goto fail;
-    goto fail; // <-- not clearly not under the "if".
-    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
-        goto fail;
-    ```
+* Before filing a bug, or if you want to understand how work on the
+  formatter is managed, see how we [track issues][].
 
-[gotofail]: https://gotofail.com/
-
-### I don't like the output!
-
-First of all, that's not a question. But, yes, sometimes you may dislike the
-output of the formatter. This may be a bug or it may be a deliberate stylistic
-choice of the formatter that you disagree with. The simplest way to find out is
-to file an [issue][].
-
-[issue]: https://github.com/dart-lang/dart_style/issues
-
-Now that the formatter is fairly mature, it's more likely that the output is
-deliberate. If your bug gets closed as "as designed", try not to be too sad.
-Even if the formatter doesn't follow your personal preferences, what it *does*
-do is spare you the effort of hand-formatting, and ensure your code is
-*consistently* formatted. I hope you'll appreciate the real value in both of
-those.
-
-### How stable is it?
-
-You can rely on the formatter to not break your code or change its semantics.
-If it does do so, this is a critical bug and we'll fix it quickly.
-
-The rules the formatter uses to determine the "best" way to split a line may
-change over time. We don't promise that code produced by the formatter today
-will be identical to the same code run through a later version of the formatter.
-We do hope that you'll like the output of the later version more.
-
-### Why can't I tell the formatter to ignore a region of code?
-
-Even a really sophisticated formatter can't beat a human in *all* cases. Our
-semantic knowledge of the code can let us show more than the formatter can. One
-escape hatch would be to have a comment telling the formatter "leave this
-alone".
-
-This might help the fourth goal above, but does so at the expense of the first
-three. We want code that is *consistent* and we want you to stop thinking about
-formatting. If you can decide to turn off the formatter, now you have regions
-of code that are inconsistent by design.
-
-Further, you're right back into debates about how the code in there should be
-formatted, with the extra bonus of now debating whether or not that annotation
-should be used and where. None of this is making your life better.
-
-Yes, *maybe* you can hand-format some things better than the formatter. (Though,
-in most cases where users have asked for this, I've seen formatting errors in
-the examples they provided!) But does doing that really add enough value to
-make up for re-opening that can of worms?
-
-### Why does the formatter mess up my collection literals?
-
-Large collection literals are often used to define big chunks of structured
-data, like:
-
-```dart
-/// Maps ASCII character values to what kind of character they represent.
-const characterTypes = const [
-  other, other, other, other, other, other, other, other,
-  other, white, white, other, other, white,              
-  other, other, other, other, other, other, other, other,
-  other, other, other, other, other, other, other, other,
-  other, other, white,                                   
-  punct, other, punct, punct, punct, punct, other,       
-  brace, brace, punct, punct, comma, punct, punct, punct,
-  digit, digit, digit, digit, digit,                     
-  digit, digit, digit, digit, digit,                     
-  punct, punct, punct, punct, punct, punct, punct,       
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, brace, punct, brace, punct, alpha, other,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, brace, punct, brace, punct               
-];
-```
-
-The formatter doesn't know those newlines are meaningful, so it wipes it out
-to:
-
-```dart
-/// Maps ASCII character values to what kind of character they represent.
-const characterTypes = const [
-  other,
-  other,
-  other,
-  
-  // lots more ...
-  
-  punct,
-  brace,
-  punct             
-];
-```
-
-In many cases, ignoring these newlines is a good thing. If you've removed a few
-items from a list, it's a win for the formatter to repack it into one line if
-it fits. But here it clearly loses useful information.
-
-Fortunately, in most cases, structured collections like this have comments
-describing their structure:
-
-```dart
-const characterTypes = const [
-  other, other, other, other, other, other, other, other,
-  other, white, white, other, other, white,
-  other, other, other, other, other, other, other, other,
-  other, other, other, other, other, other, other, other,
-  other, other, white,
-  punct, other, punct, punct, punct, punct, other, //          !"#$%&´
-  brace, brace, punct, punct, comma, punct, punct, punct, //   ()*+,-./
-  digit, digit, digit, digit, digit, //                        01234
-  digit, digit, digit, digit, digit, //                        56789
-  punct, punct, punct, punct, punct, punct, punct, //          :;<=>?@
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, //   ABCDEFGH
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, brace, punct, brace, punct, alpha, other, //   YZ[\]^_'
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, //   abcdefgh
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha,
-  alpha, alpha, brace, punct, brace, punct  //                 yz{|}~
-];
-```
-
-In that case, the formatter is smart enough to recognize this and preserve your
-original newlines. So, if you have a collection that you have carefully split
-into lines, add at least one line comment somewhere inside it to get it to
-preserve all of the newlines in it.
-
-### Why doesn't the formatter handle multi-line `if` statements better?
-
-If you have a statement like:
-
-```dart
-if (someVeryLongConditional || anotherLongConditional) function(argument, argument);
-```
-
-It will format it like:
-
-```dart
-if (someVeryLongConditional || anotherLongConditional) function(
-    argument, argument);
-```
-
-You might expect it to break before `function`. But the Dart style guide
-explicitly forbids multi-line `if` statements that do not use `{}` bodies.
-Given that, there's never a reason for the formatter to allow splitting after
-the condition. This is true of other control flow statements too, of course.
-
-### Why doesn't the formatter add curlies or otherwise clean up code then?
-
-The formatter has a simple, restricted charter: it rewrites *only the
-non-semantic whitespace of your program.* It makes absolutely no other changes
-to your code.
-
-This helps keep the scope of the project limited. The set of "clean-ups" you
-may want to do is unbounded and much fuzzier to define.
-
-It also makes it more reliable to run the formatter automatically in things
-like presubmit scripts where a human may not be vetting the output. If the
-formatter only touches whitespace, it's easier for a human to trust its output.
+[faq]: https://github.com/dart-lang/dart_style/wiki/FAQ
+[track issues]: https://github.com/dart-lang/dart_style/wiki/Tracking-issues
diff --git a/packages/dart_style/bin/format.dart b/packages/dart_style/bin/format.dart
index cd97fb0..8d179c1 100644
--- a/packages/dart_style/bin/format.dart
+++ b/packages/dart_style/bin/format.dart
@@ -6,19 +6,27 @@
 import 'dart:io';
 
 import 'package:args/args.dart';
+
 import 'package:dart_style/src/dart_formatter.dart';
 import 'package:dart_style/src/formatter_exception.dart';
 import 'package:dart_style/src/formatter_options.dart';
 import 'package:dart_style/src/io.dart';
 import 'package:dart_style/src/source_code.dart';
 
+// Note: The following line of code is modified by tool/grind.dart.
+const version = "0.2.1";
+
 void main(List<String> args) {
   var parser = new ArgParser(allowTrailingOptions: true);
 
   parser.addFlag("help",
       abbr: "h", negatable: false, help: "Shows usage information.");
+  parser.addFlag("version",
+      negatable: false, help: "Shows version information.");
   parser.addOption("line-length",
       abbr: "l", help: "Wrap lines longer than this.", defaultsTo: "80");
+  parser.addOption("indent",
+      abbr: "i", help: "Spaces of leading indentation.", defaultsTo: "0");
   parser.addOption("preserve",
       help: 'Selection to preserve, formatted as "start:length".');
   parser.addFlag("dry-run",
@@ -33,6 +41,8 @@
       abbr: "m",
       negatable: false,
       help: "Produce machine-readable JSON output.");
+  parser.addFlag("profile",
+      negatable: false, help: "Display profile times after running.");
   parser.addFlag("follow-links",
       negatable: false,
       help: "Follow links to files and directories.\n"
@@ -54,6 +64,11 @@
     return;
   }
 
+  if (argResults["version"]) {
+    print(version);
+    return;
+  }
+
   // Can only preserve a selection when parsing from stdin.
   var selection;
 
@@ -100,8 +115,11 @@
     reporter = OutputReporter.printJson;
   }
 
-  var pageWidth;
+  if (argResults["profile"]) {
+    reporter = new ProfileReporter(reporter);
+  }
 
+  var pageWidth;
   try {
     pageWidth = int.parse(argResults["line-length"]);
   } on FormatException catch (_) {
@@ -111,16 +129,32 @@
         '"${argResults['line-length']}".');
   }
 
+  var indent;
+
+  try {
+    indent = int.parse(argResults["indent"]);
+    if (indent < 0 || indent.toInt() != indent) throw new FormatException();
+  } on FormatException catch (_) {
+    usageError(
+        parser,
+        '--indent must be a non-negative integer, was '
+        '"${argResults['indent']}".');
+  }
+
   var followLinks = argResults["follow-links"];
 
   var options = new FormatterOptions(reporter,
-      pageWidth: pageWidth, followLinks: followLinks);
+      indent: indent, pageWidth: pageWidth, followLinks: followLinks);
 
   if (argResults.rest.isEmpty) {
     formatStdin(options, selection);
   } else {
     formatPaths(options, argResults.rest);
   }
+
+  if (argResults["profile"]) {
+    (reporter as ProfileReporter).showProfile();
+  }
 }
 
 List<int> parseSelection(String selection) {
@@ -147,15 +181,17 @@
 
   var input = new StringBuffer();
   stdin.transform(new Utf8Decoder()).listen(input.write, onDone: () {
-    var formatter = new DartFormatter(pageWidth: options.pageWidth);
+    var formatter =
+        new DartFormatter(indent: options.indent, pageWidth: options.pageWidth);
     try {
+      options.reporter.beforeFile(null, "<stdin>");
       var source = new SourceCode(input.toString(),
           uri: "stdin",
           selectionStart: selectionStart,
           selectionLength: selectionLength);
       var output = formatter.formatSource(source);
       options.reporter
-          .showFile(null, "<stdin>", output, changed: source != output);
+          .afterFile(null, "<stdin>", output, changed: source != output);
       return true;
     } on FormatterException catch (err) {
       stderr.writeln(err.message());
diff --git a/packages/dart_style/codereview.settings b/packages/dart_style/codereview.settings
new file mode 100644
index 0000000..25510f0
--- /dev/null
+++ b/packages/dart_style/codereview.settings
@@ -0,0 +1,3 @@
+CODE_REVIEW_SERVER: https://codereview.chromium.org/
+VIEW_VC: https://github.com/dart-lang/dart_style/commit/
+CC_LIST: reviews@dartlang.org
diff --git a/packages/dart_style/example/format.dart b/packages/dart_style/example/format.dart
index 4eec856..6d3ea61 100644
--- a/packages/dart_style/example/format.dart
+++ b/packages/dart_style/example/format.dart
@@ -44,10 +44,6 @@
       result = formatter.formatStatement(source);
     }
 
-    if (debug.useAnsiColors) {
-      result = result.replaceAll(" ", debug.gray(debug.unicodeMidDot));
-    }
-
     drawRuler("before", pageWidth);
     print(source);
     drawRuler("after", pageWidth);
diff --git a/packages/dart_style/lib/src/._error_listener.dart b/packages/dart_style/lib/src/._error_listener.dart
deleted file mode 100644
index bcc5ac5..0000000
--- a/packages/dart_style/lib/src/._error_listener.dart
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/lib/src/._formatter_options.dart b/packages/dart_style/lib/src/._formatter_options.dart
deleted file mode 100644
index 04ab7e8..0000000
--- a/packages/dart_style/lib/src/._formatter_options.dart
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/lib/src/argument_list_visitor.dart b/packages/dart_style/lib/src/argument_list_visitor.dart
index c45b737..b071987 100644
--- a/packages/dart_style/lib/src/argument_list_visitor.dart
+++ b/packages/dart_style/lib/src/argument_list_visitor.dart
@@ -4,7 +4,10 @@
 
 library dart_style.src.argument_list_visitor;
 
+import 'dart:math' as math;
+
 import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/src/generated/scanner.dart';
 
 import 'chunk.dart';
 import 'rule/argument.dart';
@@ -37,25 +40,13 @@
       _node.arguments.length == 1 && _node.arguments.single is! NamedExpression;
 
   /// Whether this argument list has any collection or block function arguments.
+  // TODO(rnystrom): Returning true based on collections is non-optimal. It
+  // forces a method chain to break into two but the result collection may not
+  // actually split which can lead to a method chain that's allowed to break
+  // where it shouldn't.
   bool get hasBlockArguments =>
       _arguments._collections.isNotEmpty || _functions != null;
 
-  /// Whether this argument list should force the containing method chain to
-  /// add a level of block nesting.
-  bool get nestMethodArguments {
-    // If there are block arguments, we don't want the method to force them to
-    // the right.
-    if (hasBlockArguments) return false;
-
-    // Corner case: If there is just a single argument, don't bump the nesting.
-    // This lets us avoid spurious indentation in cases like:
-    //
-    //     object.method(function(() {
-    //       body;
-    //     }));
-    return _node.arguments.length > 1;
-  }
-
   factory ArgumentListVisitor(SourceVisitor visitor, ArgumentList node) {
     // Look for a single contiguous range of block function arguments.
     var functionsStart;
@@ -151,8 +142,8 @@
     if (_isSingle) _visitor.builder.endSpan();
   }
 
-  /// Returns `true` if [expression] is a [FunctionExpression] with a block
-  /// body.
+  /// Returns `true` if [expression] is a [FunctionExpression] with a non-empty
+  /// block body.
   static bool _isBlockFunction(Expression expression) {
     if (expression is NamedExpression) {
       expression = (expression as NamedExpression).expression;
@@ -166,10 +157,23 @@
       return _isBlockFunction(expression.argumentList.arguments.single);
     }
 
-    // Curly body functions are.
+    if (expression is InstanceCreationExpression) {
+      if (expression.argumentList.arguments.length != 1) return false;
+
+      return _isBlockFunction(expression.argumentList.arguments.single);
+    }
+
+    // Must be a function.
     if (expression is! FunctionExpression) return false;
+
+    // With a curly body.
     var function = expression as FunctionExpression;
-    return function.body is BlockFunctionBody;
+    if (function.body is! BlockFunctionBody) return false;
+
+    // That isn't empty.
+    var body = function.body as BlockFunctionBody;
+    return body.block.statements.isNotEmpty ||
+        body.block.rightBracket.precedingComments != null;
   }
 
   /// Returns `true` if [expression] is a valid method invocation target for
@@ -206,8 +210,9 @@
   /// The named arguments, in order.
   final List<Expression> _named;
 
-  /// The arguments that are collection literals that get special formatting.
-  final Set<Expression> _collections;
+  /// Maps each argument that is a collection literal that get special
+  /// formatting to the token for the collection's open bracket.
+  final Map<Expression, Token> _collections;
 
   /// The number of leading collections.
   ///
@@ -220,16 +225,12 @@
   final int _trailingCollections;
 
   /// The rule used to split the bodies of all of the collection arguments.
-  Rule get _collectionRule {
-    // Lazy initialize.
-    if (_collectionRuleField == null && _collections.isNotEmpty) {
-      _collectionRuleField = new SimpleRule(cost: Cost.splitCollections);
-    }
+  Rule get collectionRule => _collectionRule;
+  Rule _collectionRule;
 
-    return _collectionRuleField;
-  }
-
-  Rule _collectionRuleField;
+  /// The most recent chunk that split before an argument.
+  Chunk get previousSplit => _previousSplit;
+  Chunk _previousSplit;
 
   bool get _hasMultipleArguments => _positional.length + _named.length > 1;
 
@@ -240,12 +241,16 @@
         arguments.takeWhile((arg) => arg is! NamedExpression).toList();
     var named = arguments.skip(positional.length).toList();
 
-    var collections = arguments.where(_isCollectionArgument).toSet();
+    var collections = {};
+    for (var argument in arguments) {
+      var bracket = _getCollectionBracket(argument);
+      if (bracket != null) collections[argument] = bracket;
+    }
 
     // Count the leading arguments that are collection literals.
     var leadingCollections = 0;
     for (var argument in arguments) {
-      if (!collections.contains(argument)) break;
+      if (!collections.containsKey(argument)) break;
       leadingCollections++;
     }
 
@@ -253,21 +258,11 @@
     var trailingCollections = 0;
     if (leadingCollections != arguments.length) {
       for (var argument in arguments.reversed) {
-        if (!collections.contains(argument)) break;
+        if (!collections.containsKey(argument)) break;
         trailingCollections++;
       }
     }
 
-    // If only some of the named arguments are collections, treat none of them
-    // specially. Avoids cases like:
-    //
-    //     function(
-    //         a: arg,
-    //         b: [
-    //       ...
-    //     ]);
-    if (trailingCollections < named.length) trailingCollections = 0;
-
     // Collections must all be a prefix or suffix of the argument list (and not
     // both).
     if (leadingCollections != collections.length) leadingCollections = 0;
@@ -286,6 +281,10 @@
       this._collections, this._leadingCollections, this._trailingCollections);
 
   void visit(SourceVisitor visitor) {
+    if (_collections.isNotEmpty) {
+      _collectionRule = new Rule(Cost.splitCollections);
+    }
+
     var rule = _visitPositional(visitor);
     _visitNamed(visitor, rule);
   }
@@ -299,85 +298,80 @@
     if (_positional.length == 1) {
       rule = new SinglePositionalRule(_collectionRule,
           splitsOnInnerRules: _allArguments.length > 1 &&
-              !_isCollectionArgument(_positional.first));
+              !_collections.containsKey(_positional.first));
     } else {
-      // Only count the positional bodies in the positional rule.
-      var leadingPositional = _leadingCollections;
-      if (_leadingCollections == _positional.length + _named.length) {
-        leadingPositional -= _named.length;
-      }
-
-      var trailingPositional = _trailingCollections - _named.length;
+      // Only count the collections in the positional rule.
+      var leadingCollections =
+          math.min(_leadingCollections, _positional.length);
+      var trailingCollections =
+          math.max(_trailingCollections - _named.length, 0);
       rule = new MultiplePositionalRule(
-          _collectionRule, leadingPositional, trailingPositional);
+          _collectionRule, leadingCollections, trailingCollections);
     }
 
-    visitor.builder.startRule(rule);
-
-    var chunk;
-    if (_isFirstArgument(_positional.first)) {
-      chunk = visitor.zeroSplit();
-    } else {
-      chunk = visitor.split();
-    }
-    rule.beforeArgument(chunk);
-
-    // Try to not split the arguments.
-    visitor.builder.startSpan(Cost.positionalArguments);
-
-    for (var argument in _positional) {
-      _visitArgument(visitor, rule, argument);
-
-      // Positional arguments split independently.
-      if (argument != _positional.last) {
-        rule.beforeArgument(visitor.split());
-      }
-    }
-
-    visitor.builder.endSpan();
-    visitor.builder.endRule();
-
+    _visitArguments(visitor, _positional, rule);
     return rule;
   }
 
   /// Writes the named arguments, if any.
-  void _visitNamed(SourceVisitor visitor, PositionalRule rule) {
+  void _visitNamed(SourceVisitor visitor, PositionalRule positionalRule) {
     if (_named.isEmpty) return;
 
-    var positionalRule = rule;
-    var namedRule = new NamedRule(_collectionRule);
-    visitor.builder.startRule(namedRule);
+    // Only count the collections in the named rule.
+    var leadingCollections =
+        math.max(_leadingCollections - _positional.length, 0);
+    var trailingCollections = math.min(_trailingCollections, _named.length);
+    var namedRule =
+        new NamedRule(_collectionRule, leadingCollections, trailingCollections);
 
     // Let the positional args force the named ones to split.
     if (positionalRule != null) {
       positionalRule.setNamedArgsRule(namedRule);
     }
 
-    // Split before the first named argument.
-    namedRule.beforeArguments(
-        visitor.builder.split(space: !_isFirstArgument(_named.first)));
+    _visitArguments(visitor, _named, namedRule);
+  }
 
-    for (var argument in _named) {
-      _visitArgument(visitor, namedRule, argument);
+  void _visitArguments(
+      SourceVisitor visitor, List<Expression> arguments, ArgumentRule rule) {
+    visitor.builder.startRule(rule);
+
+    // Split before the first argument.
+    _previousSplit =
+        visitor.builder.split(space: !_isFirstArgument(arguments.first));
+    rule.beforeArgument(_previousSplit);
+
+    // Try to not split the positional arguments.
+    if (arguments == _positional) {
+      visitor.builder.startSpan(Cost.positionalArguments);
+    }
+
+    for (var argument in arguments) {
+      _visitArgument(visitor, rule, argument);
 
       // Write the split.
-      if (argument != _named.last) visitor.split();
+      if (argument != arguments.last) {
+        _previousSplit = visitor.split();
+        rule.beforeArgument(_previousSplit);
+      }
     }
 
+    if (arguments == _positional) visitor.builder.endSpan();
+
     visitor.builder.endRule();
   }
 
   void _visitArgument(
       SourceVisitor visitor, ArgumentRule rule, Expression argument) {
     // If we're about to write a collection argument, handle it specially.
-    if (_collections.contains(argument)) {
+    if (_collections.containsKey(argument)) {
       if (rule != null) rule.beforeCollection();
 
       // Tell it to use the rule we've already created.
-      visitor.setNextLiteralBodyRule(_collectionRule);
+      visitor.beforeCollection(_collections[argument], this);
     } else if (_hasMultipleArguments) {
-      // Corner case: If there is just a single argument, don't bump the
-      // nesting. This lets us avoid spurious indentation in cases like:
+      // Edge case: If there is just a single argument, don't bump the nesting.
+      // This lets us avoid spurious indentation in cases like:
       //
       //     function(function(() {
       //       body;
@@ -387,7 +381,7 @@
 
     visitor.visit(argument);
 
-    if (_collections.contains(argument)) {
+    if (_collections.containsKey(argument)) {
       if (rule != null) rule.afterCollection();
     } else if (_hasMultipleArguments) {
       visitor.builder.endBlockArgumentNesting();
@@ -403,17 +397,22 @@
 
   bool _isLastArgument(Expression argument) => argument == _allArguments.last;
 
-  /// Returns true if [expression] denotes a collection literal argument.
+  /// Returns the token for the left bracket if [expression] denotes a
+  /// collection literal argument.
   ///
   /// Similar to block functions, collection arguments can get special
   /// indentation to make them look more statement-like.
-  static bool _isCollectionArgument(Expression expression) {
+  static Token _getCollectionBracket(Expression expression) {
     if (expression is NamedExpression) {
       expression = (expression as NamedExpression).expression;
     }
 
     // TODO(rnystrom): Should we step into parenthesized expressions?
 
-    return expression is ListLiteral || expression is MapLiteral;
+    if (expression is ListLiteral) return expression.leftBracket;
+    if (expression is MapLiteral) return expression.leftBracket;
+
+    // Not a collection literal.
+    return null;
   }
 }
diff --git a/packages/dart_style/lib/src/call_chain_visitor.dart b/packages/dart_style/lib/src/call_chain_visitor.dart
index 36facca..7b7fb26 100644
--- a/packages/dart_style/lib/src/call_chain_visitor.dart
+++ b/packages/dart_style/lib/src/call_chain_visitor.dart
@@ -8,6 +8,7 @@
 
 import 'argument_list_visitor.dart';
 import 'rule/argument.dart';
+import 'rule/rule.dart';
 import 'source_visitor.dart';
 
 /// Helper class for [SourceVisitor] that handles visiting and writing a
@@ -32,12 +33,58 @@
   /// order that they appear in the source.
   final List<Expression> _calls;
 
+  /// The method calls containing block function literals that break the method
+  /// chain and escape its indentation.
+  ///
+  ///     receiver.a().b().c(() {
+  ///       ;
+  ///     }).d(() {
+  ///       ;
+  ///     }).e();
+  ///
+  /// Here, it will contain `c` and `d`.
+  ///
+  /// The block calls must be contiguous and must be a suffix of the list of
+  /// calls (except for the one allowed hanging call). Otherwise, none of them
+  /// are treated as block calls:
+  ///
+  ///     receiver
+  ///         .a()
+  ///         .b(() {
+  ///           ;
+  ///         })
+  ///         .c(() {
+  ///           ;
+  ///         })
+  ///         .d()
+  ///         .e();
+  final List<Expression> _blockCalls;
+
+  /// If there is one or more block calls and a single chained expression after
+  /// that, this will be that expression.
+  ///
+  ///     receiver.a().b().c(() {
+  ///       ;
+  ///     }).d(() {
+  ///       ;
+  ///     }).e();
+  ///
+  /// We allow a single hanging call after the blocks because it will never
+  /// need to split before its `.` and this accommodates the common pattern of
+  /// a trailing `toList()` or `toSet()` after a series of higher-order methods
+  /// on an iterable.
+  final Expression _hangingCall;
+
   /// Whether or not a [Rule] is currently active for the call chain.
   bool _ruleEnabled = false;
 
   /// Whether or not the span wrapping the call chain is currently active.
   bool _spanEnded = false;
 
+  /// After the properties are visited (if there are any), this will be the
+  /// rule used to split between them.
+  PositionalRule _propertyRule;
+
   /// Creates a new call chain visitor for [visitor] starting with [node].
   ///
   /// The [node] is the outermost expression containing the chained "."
@@ -51,14 +98,25 @@
     flatten(expression) {
       target = expression;
 
-      if (expression is MethodInvocation && expression.target != null) {
-        flatten(expression.target);
+      // Treat index expressions where the target is a valid call in a method
+      // chain as being part of the call. Handles cases like:
+      //
+      //     receiver
+      //         .property
+      //         .property[0]
+      //         .property
+      //         .method()[1][2];
+      var call = expression;
+      while (call is IndexExpression) call = call.target;
+
+      if (call is MethodInvocation && call.target != null) {
+        flatten(call.target);
         calls.add(expression);
-      } else if (expression is PropertyAccess && expression.target != null) {
-        flatten(expression.target);
+      } else if (call is PropertyAccess && call.target != null) {
+        flatten(call.target);
         calls.add(expression);
-      } else if (expression is PrefixedIdentifier) {
-        flatten(expression.prefix);
+      } else if (call is PrefixedIdentifier) {
+        flatten(call.prefix);
         calls.add(expression);
       }
     }
@@ -74,17 +132,60 @@
     //       .length;
     var properties = [];
     if (target is SimpleIdentifier) {
-      properties =
-          calls.takeWhile((call) => call is! MethodInvocation).toList();
+      properties = calls.takeWhile((call) {
+        // Step into index expressions to see what the index is on.
+        while (call is IndexExpression) call = call.target;
+        return call is! MethodInvocation;
+      }).toList();
     }
 
     calls.removeRange(0, properties.length);
 
-    return new CallChainVisitor._(visitor, target, properties, calls);
+    // Separate out the block calls, if there are any.
+    var blockCalls;
+    var hangingCall;
+
+    var inBlockCalls = false;
+    for (var call in calls) {
+      // See if this call is a method call whose arguments are block formatted.
+      var isBlockCall = false;
+      if (call is MethodInvocation) {
+        var args = new ArgumentListVisitor(visitor, call.argumentList);
+        isBlockCall = args.hasBlockArguments;
+      }
+
+      if (isBlockCall) {
+        inBlockCalls = true;
+        if (blockCalls == null) blockCalls = [];
+        blockCalls.add(call);
+      } else if (inBlockCalls) {
+        // We found a non-block call after a block call.
+        if (call == calls.last) {
+          // It's the one allowed hanging one, so it's OK.
+          hangingCall = call;
+          break;
+        }
+
+        // Don't allow any of the calls to be block formatted.
+        blockCalls = null;
+        break;
+      }
+    }
+
+    if (blockCalls != null) {
+      for (var blockCall in blockCalls) calls.remove(blockCall);
+    }
+
+    if (hangingCall != null) {
+      calls.remove(hangingCall);
+    }
+
+    return new CallChainVisitor._(
+        visitor, target, properties, calls, blockCalls, hangingCall);
   }
 
-  CallChainVisitor._(
-      this._visitor, this._target, this._properties, this._calls);
+  CallChainVisitor._(this._visitor, this._target, this._properties, this._calls,
+      this._blockCalls, this._hangingCall);
 
   /// Builds chunks for the call chain.
   ///
@@ -100,6 +201,19 @@
     // Try to keep the entire method invocation one line.
     _visitor.builder.startSpan();
 
+    // If a split in the target expression forces the first `.` to split, then
+    // start the rule now so that it surrounds the target.
+    var splitOnTarget = _forcesSplit(_target);
+
+    if (splitOnTarget) {
+      if (_properties.length > 1) {
+        _propertyRule = new MultiplePositionalRule(null, 0, 0);
+        _visitor.builder.startLazyRule(_propertyRule);
+      } else if (_calls.isNotEmpty) {
+        _enableRule(lazy: true);
+      }
+    }
+
     _visitor.visit(_target);
 
     // Leading properties split like positional arguments: either not at all,
@@ -108,39 +222,138 @@
       _visitor.soloZeroSplit();
       _writeCall(_properties.single);
     } else if (_properties.length > 1) {
-      var argRule = new MultiplePositionalRule(null, 0, 0);
-      _visitor.builder.startRule(argRule);
+      if (!splitOnTarget) {
+        _propertyRule = new MultiplePositionalRule(null, 0, 0);
+        _visitor.builder.startRule(_propertyRule);
+      }
 
       for (var property in _properties) {
-        argRule.beforeArgument(_visitor.zeroSplit());
+        _propertyRule.beforeArgument(_visitor.zeroSplit());
         _writeCall(property);
       }
 
       _visitor.builder.endRule();
     }
 
-    // The remaining chain of calls generally split atomically (either all or
-    // none), except that block arguments may split a chain into two parts.
+    // Indent any block arguments in the chain that don't get special formatting
+    // below. Only do this if there is more than one argument to avoid spurious
+    // indentation in cases like:
+    //
+    //     object.method(wrapper(() {
+    //       body;
+    //     });
+    // TODO(rnystrom): Come up with a less arbitrary way to express this?
+    if (_calls.length > 1) _visitor.builder.startBlockArgumentNesting();
+
+    // The chain of calls splits atomically (either all or none). Any block
+    // arguments inside them get indented to line up with the `.`.
     for (var call in _calls) {
       _enableRule();
       _visitor.zeroSplit();
       _writeCall(call);
     }
 
+    if (_calls.length > 1) _visitor.builder.endBlockArgumentNesting();
+
+    // If there are block calls, end the chain and write those without any
+    // extra indentation.
+    if (_blockCalls != null) {
+      _enableRule();
+      _visitor.zeroSplit();
+      _disableRule();
+
+      for (var blockCall in _blockCalls) {
+        _writeBlockCall(blockCall);
+      }
+
+      // If there is a hanging call after the last block, write it without any
+      // split before the ".".
+      if (_hangingCall != null) {
+        _writeCall(_hangingCall);
+      }
+    }
+
     _disableRule();
     _endSpan();
 
     if (unnest) _visitor.builder.unnest();
   }
 
+  /// Returns `true` if the method chain should split if a split occurs inside
+  /// [expression].
+  ///
+  /// In most cases, splitting in a method chain's target forces the chain to
+  /// split too:
+  ///
+  ///      receiver(very, long, argument,
+  ///              list)                    // <-- Split here...
+  ///          .method();                   //     ...forces split here.
+  ///
+  /// However, if the target is a collection or function literal (or an
+  /// argument list ending in one of those), we don't want to split:
+  ///
+  ///      receiver(inner(() {
+  ///        ;
+  ///      }).method();                     // <-- Unsplit.
+  bool _forcesSplit(Expression expression) {
+    // TODO(rnystrom): Other cases we may want to consider handling and
+    // recursing into:
+    // * ParenthesizedExpression.
+    // * The right operand in an infix operator call.
+    // * The body of a `=>` function.
+
+    // Don't split right after a collection literal.
+    if (expression is ListLiteral) return false;
+    if (expression is MapLiteral) return false;
+
+    // Don't split right after a non-empty curly-bodied function.
+    if (expression is FunctionExpression) {
+      if (expression.body is! BlockFunctionBody) return false;
+
+      return (expression.body as BlockFunctionBody).block.statements.isEmpty;
+    }
+
+    // If the expression ends in an argument list, base the splitting on the
+    // last argument.
+    var argumentList;
+    if (expression is MethodInvocation) {
+      argumentList = expression.argumentList;
+    } else if (expression is InstanceCreationExpression) {
+      argumentList = expression.argumentList;
+    } else if (expression is FunctionExpressionInvocation) {
+      argumentList = expression.argumentList;
+    }
+
+    // Any other kind of expression always splits.
+    if (argumentList == null) return true;
+    if (argumentList.arguments.isEmpty) return true;
+
+    var argument = argumentList.arguments.last;
+    if (argument is NamedExpression) argument = argument.expression;
+
+    // TODO(rnystrom): This logic is similar (but not identical) to
+    // ArgumentListVisitor.hasBlockArguments. They overlap conceptually and
+    // both have their own peculiar heuristics. It would be good to unify and
+    // rationalize them.
+
+    return _forcesSplit(argument);
+  }
+
   /// Writes [call], which must be one of the supported expression types.
   void _writeCall(Expression call) {
-    if (call is MethodInvocation) {
+    if (call is IndexExpression) {
+      _visitor.builder.nestExpression();
+      _writeCall(call.target);
+      _visitor.finishIndexExpression(call);
+      _visitor.builder.unnest();
+    } else if (call is MethodInvocation) {
       _writeInvocation(call);
     } else if (call is PropertyAccess) {
-      _writePropertyAccess(call);
+      _visitor.token(call.operator);
+      _visitor.visit(call.propertyName);
     } else if (call is PrefixedIdentifier) {
-      _writePrefixedIdentifier(call);
+      _visitor.token(call.period);
+      _visitor.visit(call.identifier);
     } else {
       // Unexpected type.
       assert(false);
@@ -151,38 +364,15 @@
     _visitor.token(invocation.operator);
     _visitor.token(invocation.methodName.token);
 
-    // If a method's argument list includes any block arguments, there's a
-    // good chance it will split. Treat the chains before and after that as
-    // separate unrelated method chains.
-    //
-    // This is kind of a hack since it treats methods before and after a
-    // collection literal argument differently even when the collection
-    // doesn't split, but it works out OK in practice.
-    //
-    // Doing something more precise would require setting up a bunch of complex
-    // constraints between various rules. You'd basically have to say "if the
-    // block argument splits then allow the chain after it to split
-    // independently, otherwise force it to follow the previous chain".
-    var args = new ArgumentListVisitor(_visitor, invocation.argumentList);
-
-    // Stop the rule after the last call, but before its arguments. This
-    // allows unsplit chains where the last argument list wraps, like:
+    // If we don't have any block calls, stop the rule after the last method
+    // call name, but before its arguments. This allows unsplit chains where
+    // the last argument list wraps, like:
     //
     //     foo().bar().baz(
     //         argument, list);
-    //
-    // Also stop the rule to split the argument list at any call with
-    // block arguments. This makes for nicer chains of higher-order method
-    // calls, like:
-    //
-    //     items.map((element) {
-    //       ...
-    //     }).where((element) {
-    //       ...
-    //     });
-    if (invocation == _calls.last || args.hasBlockArguments) _disableRule();
-
-    if (args.nestMethodArguments) _visitor.builder.startBlockArgumentNesting();
+    if (_blockCalls == null && _calls.isNotEmpty && invocation == _calls.last) {
+      _disableRule();
+    }
 
     // For a single method call on an identifier, stop the span before the
     // arguments to make it easier to keep the call name with the target. In
@@ -202,23 +392,18 @@
     // there looks really odd.
     if (_properties.isEmpty &&
         _calls.length == 1 &&
+        _blockCalls == null &&
         _target is SimpleIdentifier) {
       _endSpan();
     }
 
     _visitor.visit(invocation.argumentList);
-
-    if (args.nestMethodArguments) _visitor.builder.endBlockArgumentNesting();
   }
 
-  void _writePropertyAccess(PropertyAccess property) {
-    _visitor.token(property.operator);
-    _visitor.visit(property.propertyName);
-  }
-
-  void _writePrefixedIdentifier(PrefixedIdentifier prefix) {
-    _visitor.token(prefix.period);
-    _visitor.visit(prefix.identifier);
+  void _writeBlockCall(MethodInvocation invocation) {
+    _visitor.token(invocation.operator);
+    _visitor.token(invocation.methodName.token);
+    _visitor.visit(invocation.argumentList);
   }
 
   /// If a [Rule] for the method chain is currently active, ends it.
@@ -230,10 +415,19 @@
   }
 
   /// Creates a new method chain [Rule] if one is not already active.
-  void _enableRule() {
+  void _enableRule({bool lazy: false}) {
     if (_ruleEnabled) return;
 
-    _visitor.builder.startRule();
+    // If the properties split, force the calls to split too.
+    var rule = new Rule();
+    if (_propertyRule != null) _propertyRule.setNamedArgsRule(rule);
+
+    if (lazy) {
+      _visitor.builder.startLazyRule(rule);
+    } else {
+      _visitor.builder.startRule(rule);
+    }
+
     _ruleEnabled = true;
   }
 
diff --git a/packages/dart_style/lib/src/chunk.dart b/packages/dart_style/lib/src/chunk.dart
index e92a85b..da6d7bb 100644
--- a/packages/dart_style/lib/src/chunk.dart
+++ b/packages/dart_style/lib/src/chunk.dart
@@ -92,9 +92,13 @@
   NestingLevel get nesting => _nesting;
   NestingLevel _nesting;
 
-  /// If this chunk marks the beginning of a block, these are the chunks
-  /// contained in the block.
-  final blockChunks = <Chunk>[];
+  /// If this chunk marks the beginning of a block, this contains the child
+  /// chunks and other data about that nested block.
+  ChunkBlock get block => _block;
+  ChunkBlock _block;
+
+  /// Whether this chunk has a [block].
+  bool get isBlock => _block != null;
 
   /// Whether it's valid to add more text to this chunk or not.
   ///
@@ -110,10 +114,6 @@
   Rule get rule => _rule;
   Rule _rule;
 
-  /// Whether this chunk is always followed by a newline or whether the line
-  /// splitter may choose to keep the next chunk on the same line.
-  bool get isHardSplit => _rule is HardSplitRule;
-
   /// Whether or not an extra blank line should be output after this chunk if
   /// it's split.
   ///
@@ -136,9 +136,9 @@
   /// If `true`, then the line after this chunk and its contained block should
   /// be flush left.
   bool get flushLeftAfter {
-    if (blockChunks.isEmpty) return _flushLeft;
+    if (!isBlock) return _flushLeft;
 
-    return blockChunks.last.flushLeftAfter;
+    return _block.chunks.last.flushLeftAfter;
   }
 
   /// Whether this chunk should append an extra space if it does not split.
@@ -165,8 +165,10 @@
   /// Does not include this chunk's own length, just the length of its child
   /// block chunks (recursively).
   int get unsplitBlockLength {
+    if (_block == null) return 0;
+
     var length = 0;
-    for (var chunk in blockChunks) {
+    for (var chunk in _block.chunks) {
       length += chunk.length + chunk.unsplitBlockLength;
     }
 
@@ -191,15 +193,6 @@
     _text += text;
   }
 
-  /// Forces this soft split to become a hard split.
-  ///
-  /// This is called on the soft splits owned by a rule that decides to harden
-  /// when it finds out another hard split occurs within its chunks.
-  void harden() {
-    _rule = new HardSplitRule();
-    spans.clear();
-  }
-
   /// Finishes off this chunk with the given [rule] and split information.
   ///
   /// This may be called multiple times on the same split since the splits
@@ -207,10 +200,10 @@
   /// preserved whitespace often overlap. When that happens, this has logic to
   /// combine that information into a single split.
   void applySplit(Rule rule, int indent, NestingLevel nesting,
-      {bool flushLeft, bool spaceWhenUnsplit, bool isDouble}) {
+      {bool flushLeft, bool isDouble, bool space}) {
     if (flushLeft == null) flushLeft = false;
-    if (spaceWhenUnsplit == null) spaceWhenUnsplit = false;
-    if (isHardSplit || rule is HardSplitRule) {
+    if (space == null) space = false;
+    if (rule.isHardened) {
       // A hard split always wins.
       _rule = rule;
     } else if (_rule == null) {
@@ -223,12 +216,28 @@
     _nesting = nesting;
     _indent = indent;
 
-    _spaceWhenUnsplit = spaceWhenUnsplit;
+    _spaceWhenUnsplit = space;
 
     // Pin down the double state, if given and we haven't already.
     if (_isDouble == null) _isDouble = isDouble;
   }
 
+  /// Turns this chunk into one that can contain a block of child chunks.
+  void makeBlock(Chunk blockArgument) {
+    assert(_block == null);
+    _block = new ChunkBlock(blockArgument);
+  }
+
+  /// Returns `true` if the block body owned by this chunk should be expression
+  /// indented given a set of rule values provided by [getValue].
+  bool indentBlock(int getValue(Rule rule)) {
+    if (_block == null) return false;
+    if (_block.argument == null) return false;
+
+    return _block.argument.rule
+        .isSplit(getValue(_block.argument.rule), _block.argument);
+  }
+
   // Mark whether this chunk can divide the range of chunks.
   void markDivide(canDivide) {
     // Should only do this once.
@@ -243,19 +252,18 @@
     if (text.isNotEmpty) parts.add(text);
 
     if (_indent != null) parts.add("indent:$_indent");
-    if (spaceWhenUnsplit) parts.add("space");
-    if (_isDouble) parts.add("double");
-    if (_flushLeft) parts.add("flush");
+    if (spaceWhenUnsplit == true) parts.add("space");
+    if (_isDouble == true) parts.add("double");
+    if (_flushLeft == true) parts.add("flush");
 
     if (_rule == null) {
       parts.add("(no split)");
-    } else if (isHardSplit) {
-      parts.add("hard");
     } else {
       parts.add(rule.toString());
+      if (rule.isHardened) parts.add("(hard)");
 
-      if (_rule.outerRules.isNotEmpty) {
-        parts.add("-> ${_rule.outerRules.join(' ')}");
+      if (_rule.constrainedRules.isNotEmpty) {
+        parts.add("-> ${_rule.constrainedRules.join(' ')}");
       }
     }
 
@@ -263,6 +271,22 @@
   }
 }
 
+/// The child chunks owned by a chunk that begins a "block" -- an actual block
+/// statement, function expression, or collection literal.
+class ChunkBlock {
+  /// If this block is for a collection literal in an argument list, this will
+  /// be the chunk preceding this literal argument.
+  ///
+  /// That chunk is owned by the argument list and if it splits, this collection
+  /// may need extra expression-level indentation.
+  final Chunk argument;
+
+  /// The child chunks in this block.
+  final List<Chunk> chunks = [];
+
+  ChunkBlock(this.argument);
+}
+
 /// Constants for the cost heuristics used to determine which set of splits is
 /// most desirable.
 class Cost {
@@ -280,8 +304,11 @@
   /// number of nested spans.
   static const normal = 1;
 
-  /// Splitting after a "=" both for assignment and initialization.
-  static const assignment = 2;
+  /// Splitting after a "=".
+  static const assign = 1;
+
+  /// Splitting after a "=" when the right-hand side is a collection or cascade.
+  static const assignBlock = 2;
 
   /// Splitting before the first argument when it happens to be a function
   /// expression with a block body.
@@ -299,6 +326,9 @@
   /// collection contents.
   static const splitCollections = 2;
 
+  /// Splitting on the "." in a named constructor.
+  static const constructorName = 3;
+
   /// Splitting before a type argument or type parameter.
   static const typeArgument = 4;
 }
diff --git a/packages/dart_style/lib/src/chunk_builder.dart b/packages/dart_style/lib/src/chunk_builder.dart
index c7ff91b..3aa95a5 100644
--- a/packages/dart_style/lib/src/chunk_builder.dart
+++ b/packages/dart_style/lib/src/chunk_builder.dart
@@ -61,9 +61,6 @@
   /// written before they start.
   final _lazyRules = <Rule>[];
 
-  /// The indexes of the chunks owned by each rule (except for hard splits).
-  final _ruleChunks = <Rule, List<int>>{};
-
   /// The nested stack of spans that are currently being written.
   final _openSpans = <OpenSpan>[];
 
@@ -101,8 +98,8 @@
   /// token pair.
   bool get needsToPreserveNewlines =>
       _pendingWhitespace == Whitespace.oneOrTwoNewlines ||
-          _pendingWhitespace == Whitespace.spaceOrNewline ||
-          _pendingWhitespace == Whitespace.splitOrNewline;
+      _pendingWhitespace == Whitespace.spaceOrNewline ||
+      _pendingWhitespace == Whitespace.splitOrNewline;
 
   /// The number of characters of code that can fit in a single line.
   int get pageWidth => _formatter.pageWidth;
@@ -151,25 +148,18 @@
 
   /// Write a split owned by the current innermost rule.
   ///
-  /// If [nesting] is given, uses that. Otherwise, uses the current nesting
-  /// level. If unsplit, it expands to a space if [space] is `true`.
-  ///
   /// If [flushLeft] is `true`, then forces the next line to start at column
   /// one regardless of any indentation or nesting.
   ///
   /// If [isDouble] is passed, forces the split to either be a single or double
   /// newline. Otherwise, leaves it indeterminate.
-  Chunk split({bool space, bool isDouble, bool flushLeft}) =>
-      _writeSplit(_rules.last, null,
-          flushLeft: flushLeft, isDouble: isDouble, spaceWhenUnsplit: space);
-
-  /// Write a split owned by the current innermost rule.
   ///
-  /// Unlike [split()], this ignores any current expression nesting. It always
-  /// indents the next line at the statement level.
-  Chunk blockSplit({bool space, bool isDouble}) =>
-      _writeSplit(_rules.last, _nesting.blockNesting,
-          isDouble: isDouble, spaceWhenUnsplit: space);
+  /// If [nest] is `false`, ignores any current expression nesting. Otherwise,
+  /// uses the current nesting level. If unsplit, it expands to a space if
+  /// [space] is `true`.
+  Chunk split({bool flushLeft, bool isDouble, bool nest, bool space}) =>
+      _writeSplit(_rules.last,
+          flushLeft: flushLeft, isDouble: isDouble, nest: nest, space: space);
 
   /// Outputs the series of [comments] and associated whitespace that appear
   /// before [token] (which is not written by this).
@@ -257,9 +247,9 @@
       } else {
         // The comment starts a line, so make sure it stays on its own line.
         _writeHardSplit(
-            nest: true,
             flushLeft: comment.flushLeft,
-            double: comment.linesBefore > 1);
+            isDouble: comment.linesBefore > 1,
+            nest: true);
       }
 
       _writeText(comment.text);
@@ -291,7 +281,7 @@
         }
       }
 
-      if (linesAfter > 0) _writeHardSplit(nest: true, double: linesAfter > 1);
+      if (linesAfter > 0) _writeHardSplit(isDouble: linesAfter > 1, nest: true);
     }
 
     // If the comment has text following it (aside from a grouping character),
@@ -368,15 +358,15 @@
     var span = new Span(openSpan.cost);
     for (var i = openSpan.start; i < end; i++) {
       var chunk = _chunks[i];
-      if (!chunk.isHardSplit) chunk.spans.add(span);
+      if (!chunk.rule.isHardened) chunk.spans.add(span);
     }
   }
 
   /// Starts a new [Rule].
   ///
-  /// If omitted, defaults to a new [SimpleRule].
+  /// If omitted, defaults to a new [Rule].
   void startRule([Rule rule]) {
-    if (rule == null) rule = new SimpleRule();
+    if (rule == null) rule = new Rule();
 
     // See if any of the rules that contain this one care if it splits.
     _rules.forEach((outer) => outer.contain(rule));
@@ -390,9 +380,9 @@
   /// first operand but not get forced to split if a comment appears before the
   /// entire expression.
   ///
-  /// If [rule] is omitted, defaults to a new [SimpleRule].
+  /// If [rule] is omitted, defaults to a new [Rule].
   void startLazyRule([Rule rule]) {
-    if (rule == null) rule = new SimpleRule();
+    if (rule == null) rule = new Rule();
 
     _lazyRules.add(rule);
   }
@@ -431,8 +421,14 @@
   ///
   /// Expressions that are more nested will get increased indentation when split
   /// if the previous line has a lower level of nesting.
-  void unnest() {
+  ///
+  /// If [now] is `false`, does not commit the nesting change until after the
+  /// next chunk of text is written.
+  void unnest({bool now}) {
+    if (now == null) now = true;
+
     _nesting.unnest();
+    if (now) _nesting.commitNesting();
   }
 
   /// Marks the selection starting point as occurring [fromEnd] characters to
@@ -469,9 +465,12 @@
   /// Starts a new block as a child of the current chunk.
   ///
   /// Nested blocks are handled using their own independent [LineWriter].
-  ChunkBuilder startBlock() {
+  ChunkBuilder startBlock(Chunk argumentChunk) {
+    var chunk = _chunks.last;
+    chunk.makeBlock(argumentChunk);
+
     var builder =
-        new ChunkBuilder._(this, _formatter, _source, _chunks.last.blockChunks);
+        new ChunkBuilder._(this, _formatter, _source, chunk.block.chunks);
 
     // A block always starts off indented one level.
     builder.indent();
@@ -488,7 +487,7 @@
   /// `true`, the block is considered to always split.
   ///
   /// Returns the previous writer for the surrounding block.
-  ChunkBuilder endBlock(HardSplitRule ignoredSplit, {bool forceSplit}) {
+  ChunkBuilder endBlock(Rule ignoredSplit, {bool forceSplit}) {
     _divideChunks();
 
     // If we don't already know if the block is going to split, see if it
@@ -502,21 +501,33 @@
           break;
         }
 
-        if (chunk.isHardSplit && chunk.rule != ignoredSplit) {
+        if (chunk.rule != null &&
+            chunk.rule.isHardened &&
+            chunk.rule != ignoredSplit) {
           forceSplit = true;
           break;
         }
       }
     }
 
+    _parent._endChildBlock(
+        firstFlushLeft: _firstFlushLeft, forceSplit: forceSplit);
+
+    return _parent;
+  }
+
+  /// Finishes off the last chunk in a child block of this parent.
+  void _endChildBlock({bool firstFlushLeft, bool forceSplit}) {
     // If there is a hard newline within the block, force the surrounding rule
     // for it so that we apply that constraint.
-    if (forceSplit) _parent.forceRules();
+    if (forceSplit) forceRules();
 
     // Write the split for the block contents themselves.
-    _parent._writeSplit(_parent._rules.last, _parent._blockArgumentNesting.last,
-        flushLeft: _firstFlushLeft);
-    return _parent;
+    var chunk = _chunks.last;
+    chunk.applySplit(rule, _nesting.indentation, _blockArgumentNesting.last,
+        flushLeft: firstFlushLeft);
+
+    if (chunk.rule.isHardened) _handleHardSplit();
   }
 
   /// Finishes writing and returns a [SourceCode] containing the final output
@@ -577,11 +588,11 @@
         break;
 
       case Whitespace.newlineFlushLeft:
-        _writeHardSplit(nest: true, flushLeft: true);
+        _writeHardSplit(flushLeft: true, nest: true);
         break;
 
       case Whitespace.twoNewlines:
-        _writeHardSplit(double: true);
+        _writeHardSplit(isDouble: true);
         break;
 
       case Whitespace.spaceOrNewline:
@@ -661,46 +672,38 @@
   /// Appends a hard split with the current indentation and nesting (the latter
   /// only if [nest] is `true`).
   ///
-  /// If [double] is `true` or `false`, forces a since or double line to be
+  /// If [double] is `true` or `false`, forces a single or double line to be
   /// output. Otherwise, it is left indeterminate.
   ///
   /// If [flushLeft] is `true`, then the split will always cause the next line
   /// to be at column zero. Otherwise, it uses the normal indentation and
   /// nesting behavior.
-  void _writeHardSplit({bool nest: false, bool double, bool flushLeft}) {
+  void _writeHardSplit({bool isDouble, bool flushLeft, bool nest: false}) {
     // A hard split overrides any other whitespace.
     _pendingWhitespace = null;
-    _writeSplit(new HardSplitRule(), nest ? null : _nesting.blockNesting,
-        flushLeft: flushLeft, isDouble: double);
+    _writeSplit(new Rule.hard(),
+        flushLeft: flushLeft, isDouble: isDouble, nest: nest);
   }
 
   /// Ends the current chunk (if any) with the given split information.
   ///
   /// Returns the chunk.
-  Chunk _writeSplit(Rule rule, NestingLevel nesting,
-      {bool flushLeft, bool isDouble, bool spaceWhenUnsplit}) {
+  Chunk _writeSplit(Rule rule,
+      {bool flushLeft, bool isDouble, bool nest, bool space}) {
+    if (nest == null) nest = true;
+
     if (_chunks.isEmpty) {
       if (flushLeft != null) _firstFlushLeft = flushLeft;
 
       return null;
     }
 
-    if (nesting == null) nesting = _nesting.nesting;
+    _chunks.last.applySplit(rule, _nesting.indentation,
+        nest ? _nesting.nesting : new NestingLevel(),
+        flushLeft: flushLeft, isDouble: isDouble, space: space);
 
-    var chunk = _chunks.last;
-    chunk.applySplit(rule, _nesting.indentation, nesting,
-        flushLeft: flushLeft,
-        isDouble: isDouble,
-        spaceWhenUnsplit: spaceWhenUnsplit);
-
-    // Keep track of which chunks are owned by the rule.
-    if (rule is! HardSplitRule) {
-      _ruleChunks.putIfAbsent(rule, () => []).add(_chunks.length - 1);
-    }
-
-    if (chunk.isHardSplit) _handleHardSplit();
-
-    return chunk;
+    if (_chunks.last.rule.isHardened) _handleHardSplit();
+    return _chunks.last;
   }
 
   /// Writes [text] to either the current chunk or a new one if the current
@@ -716,14 +719,13 @@
   /// Returns true if we can divide the chunks at [index] and line split the
   /// ones before and after that separately.
   bool _canDivideAt(int i) {
-    var chunk = _chunks[i];
-    if (!chunk.isHardSplit) return false;
-    if (chunk.nesting.isNested) return false;
-    if (chunk.blockChunks.isNotEmpty) return false;
+    // Don't divide after the last chunk.
+    if (i == _chunks.length - 1) return false;
 
-    // Make sure we don't split the line in the middle of a rule.
-    var chunks = _ruleChunks[chunk.rule];
-    if (chunks != null && chunks.any((other) => other > i)) return false;
+    var chunk = _chunks[i];
+    if (!chunk.rule.isHardened) return false;
+    if (chunk.nesting.isNested) return false;
+    if (chunk.isBlock) return false;
 
     return true;
   }
@@ -765,18 +767,16 @@
   void _hardenRules() {
     if (_hardSplitRules.isEmpty) return;
 
-    // Harden all of the rules that are constrained by [rules] as well.
-    var hardenedRules = new Set();
     walkConstraints(rule) {
-      if (hardenedRules.contains(rule)) return;
-      hardenedRules.add(rule);
+      rule.harden();
 
       // Follow this rule's constraints, recursively.
-      for (var other in _ruleChunks.keys) {
+      for (var other in rule.constrainedRules) {
         if (other == rule) continue;
 
-        if (rule.constrain(rule.fullySplitValue, other) ==
-            other.fullySplitValue) {
+        if (!other.isHardened &&
+            rule.constrain(rule.fullySplitValue, other) ==
+                other.fullySplitValue) {
           walkConstraints(other);
         }
       }
@@ -786,10 +786,11 @@
       walkConstraints(rule);
     }
 
-    // Harden every chunk that uses one of these rules.
+    // Discard spans in hardened chunks since we know for certain they will
+    // split anyway.
     for (var chunk in _chunks) {
-      if (hardenedRules.contains(chunk.rule)) {
-        chunk.harden();
+      if (chunk.rule != null && chunk.rule.isHardened) {
+        chunk.spans.clear();
       }
     }
   }
diff --git a/packages/dart_style/lib/src/dart_formatter.dart b/packages/dart_style/lib/src/dart_formatter.dart
index fc2e789..428aeec 100644
--- a/packages/dart_style/lib/src/dart_formatter.dart
+++ b/packages/dart_style/lib/src/dart_formatter.dart
@@ -60,7 +60,8 @@
     }
 
     return formatSource(
-        new SourceCode(source, uri: uri, isCompilationUnit: true)).text;
+            new SourceCode(source, uri: uri, isCompilationUnit: true))
+        .text;
   }
 
   /// Formats the given [source] string containing a single Dart statement.
@@ -109,7 +110,7 @@
       // Make sure we consumed all of the source.
       var token = node.endToken.next;
       if (token.type != TokenType.EOF) {
-        var error = new AnalysisError.con2(
+        var error = new AnalysisError(
             stringSource,
             token.offset,
             math.max(token.length, 1),
diff --git a/packages/dart_style/lib/src/debug.dart b/packages/dart_style/lib/src/debug.dart
index 47ca7fe..5d0eb2b 100644
--- a/packages/dart_style/lib/src/debug.dart
+++ b/packages/dart_style/lib/src/debug.dart
@@ -9,7 +9,6 @@
 
 import 'chunk.dart';
 import 'line_splitting/rule_set.dart';
-import 'rule/rule.dart';
 
 /// Set this to `true` to turn on diagnostic output while building chunks.
 bool traceChunkBuilder = false;
@@ -68,15 +67,16 @@
 /// Prints [chunks] to stdout, one chunk per line, with detailed information
 /// about each chunk.
 void dumpChunks(int start, List<Chunk> chunks) {
-  if (chunks.isEmpty) return;
+  if (chunks.skip(start).isEmpty) return;
 
-  // Show the spans as vertical bands over their range.
+  // Show the spans as vertical bands over their range (unless there are too
+  // many).
   var spans = new Set();
   addSpans(chunks) {
     for (var chunk in chunks) {
       spans.addAll(chunk.spans);
 
-      addSpans(chunk.blockChunks);
+      if (chunk.isBlock) addSpans(chunk.block.chunks);
     }
   }
 
@@ -84,28 +84,41 @@
 
   spans = spans.toList();
 
-  var rules = chunks
-      .map((chunk) => chunk.rule)
-      .where((rule) => rule != null && rule is! HardSplitRule)
-      .toSet();
+  var rules =
+      chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet();
 
   var rows = [];
 
-  addChunk(chunk, prefix, index) {
+  addChunk(List<Chunk> chunks, String prefix, int index) {
     var row = [];
     row.add("$prefix$index:");
 
+    var chunk = chunks[index];
     if (chunk.text.length > 70) {
       row.add(chunk.text.substring(0, 70));
     } else {
       row.add(chunk.text);
     }
 
-    var spanBars = "";
-    for (var span in spans) {
-      spanBars += chunk.spans.contains(span) ? "|" : " ";
+    if (spans.length <= 20) {
+      var spanBars = "";
+      for (var span in spans) {
+        if (chunk.spans.contains(span)) {
+          if (index == 0 || !chunks[index - 1].spans.contains(span)) {
+            spanBars += "â•–";
+          } else {
+            spanBars += "â•‘";
+          }
+        } else {
+          if (index > 0 && chunks[index - 1].spans.contains(span)) {
+            spanBars += "╜";
+          } else {
+            spanBars += " ";
+          }
+        }
+      }
+      row.add(spanBars);
     }
-    row.add(spanBars);
 
     writeIf(predicate, String callback()) {
       if (predicate) {
@@ -115,16 +128,21 @@
       }
     }
 
-    if (chunk.rule != null) {
-      row.add(chunk.isHardSplit ? "" : chunk.rule.toString());
-
-      var outerRules = chunk.rule.outerRules.toSet().intersection(rules);
-      writeIf(outerRules.isNotEmpty, () => "-> ${outerRules.join(" ")}");
-    } else {
-      row.add("(no rule)");
-
-      // Outer rules.
+    if (chunk.rule == null) {
       row.add("");
+      row.add("(no rule)");
+      row.add("");
+    } else {
+      writeIf(chunk.rule.cost != 0, () => "\$${chunk.rule.cost}");
+
+      var ruleString = chunk.rule.toString();
+      if (chunk.rule.isHardened) ruleString += "!";
+      row.add(ruleString);
+
+      var constrainedRules =
+          chunk.rule.constrainedRules.toSet().intersection(rules);
+      writeIf(constrainedRules.isNotEmpty,
+          () => "-> ${constrainedRules.join(" ")}");
     }
 
     writeIf(chunk.indent != null && chunk.indent != 0,
@@ -135,17 +153,19 @@
 
     writeIf(chunk.flushLeft != null && chunk.flushLeft, () => "flush");
 
+    writeIf(chunk.canDivide, () => "divide");
+
     rows.add(row);
 
-    for (var j = 0; j < chunk.blockChunks.length; j++) {
-      addChunk(chunk.blockChunks[j], "$prefix$index.", j);
+    if (chunk.isBlock) {
+      for (var j = 0; j < chunk.block.chunks.length; j++) {
+        addChunk(chunk.block.chunks, "$prefix$index.", j);
+      }
     }
   }
 
-  var i = start;
-  for (var chunk in chunks) {
-    addChunk(chunk, "", i);
-    i++;
+  for (var i = start; i < chunks.length; i++) {
+    addChunk(chunks, "", i);
   }
 
   var rowWidths = new List.filled(rows.first.length, 0);
@@ -172,6 +192,33 @@
   print(buffer.toString());
 }
 
+/// Shows all of the constraints between the rules used by [chunks].
+void dumpConstraints(List<Chunk> chunks) {
+  var rules =
+      chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet();
+
+  for (var rule in rules) {
+    var constrainedValues = [];
+    for (var value = 0; value < rule.numValues; value++) {
+      var constraints = [];
+      for (var other in rules) {
+        if (rule == other) continue;
+
+        var constraint = rule.constrain(value, other);
+        if (constraint != null) {
+          constraints.add("$other->$constraint");
+        }
+      }
+
+      if (constraints.isNotEmpty) {
+        constrainedValues.add("$value:(${constraints.join(' ')})");
+      }
+    }
+
+    log("$rule ${constrainedValues.join(' ')}");
+  }
+}
+
 /// Convert the line to a [String] representation.
 ///
 /// It will determine how best to split it into multiple lines of output and
@@ -187,7 +234,7 @@
       if (chunk.spaceWhenUnsplit) buffer.write(" ");
 
       // Recurse into the block.
-      writeChunksUnsplit(chunk.blockChunks);
+      if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks);
     }
   }
 
@@ -203,7 +250,7 @@
         writeIndent(splits.getColumn(i));
       }
     } else {
-      writeChunksUnsplit(chunk.blockChunks);
+      if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks);
 
       if (chunk.spaceWhenUnsplit) buffer.write(" ");
     }
diff --git a/packages/dart_style/lib/src/formatter_options.dart b/packages/dart_style/lib/src/formatter_options.dart
index 3869e8a..69a46ff 100644
--- a/packages/dart_style/lib/src/formatter_options.dart
+++ b/packages/dart_style/lib/src/formatter_options.dart
@@ -14,6 +14,9 @@
   /// The [OutputReporter] used to show the formatting results.
   final OutputReporter reporter;
 
+  /// The number of spaces of indentation to prefix the output with.
+  final int indent;
+
   /// The number of columns that formatted output should be constrained to fit
   /// within.
   final int pageWidth;
@@ -22,7 +25,7 @@
   final bool followLinks;
 
   FormatterOptions(this.reporter,
-      {this.pageWidth: 80, this.followLinks: false});
+      {this.indent: 0, this.pageWidth: 80, this.followLinks: false});
 }
 
 /// How the formatter reports the results it produces.
@@ -47,20 +50,23 @@
   /// Describe the symlink at [path] that wasn't followed.
   void showSkippedLink(String path) {}
 
-  /// Describe the hidden file at [path] that wasn't processed.
-  void showHiddenFile(String path) {}
+  /// Describe the hidden [path] that wasn't processed.
+  void showHiddenPath(String path) {}
+
+  /// Called when [file] is about to be formatted.
+  void beforeFile(File file, String label) {}
 
   /// Describe the processed file at [path] whose formatted result is [output].
   ///
   /// If the contents of the file are the same as the formatted output,
   /// [changed] will be false.
-  void showFile(File file, String label, SourceCode output, {bool changed});
+  void afterFile(File file, String label, SourceCode output, {bool changed});
 }
 
 /// Prints only the names of files whose contents are different from their
 /// formatted version.
 class _DryRunReporter extends OutputReporter {
-  void showFile(File file, String label, SourceCode output, {bool changed}) {
+  void afterFile(File file, String label, SourceCode output, {bool changed}) {
     // Only show the changed files.
     if (changed) print(label);
   }
@@ -76,11 +82,11 @@
     print("Skipping link $path");
   }
 
-  void showHiddenFile(String path) {
-    print("Skipping hidden file $path");
+  void showHiddenPath(String path) {
+    print("Skipping hidden path $path");
   }
 
-  void showFile(File file, String label, SourceCode output, {bool changed}) {
+  void afterFile(File file, String label, SourceCode output, {bool changed}) {
     // Don't add an extra newline.
     stdout.write(output.text);
   }
@@ -89,7 +95,7 @@
 /// Prints the formatted result and selection info of each file to stdout as a
 /// JSON map.
 class _PrintJsonReporter extends OutputReporter {
-  void showFile(File file, String label, SourceCode output, {bool changed}) {
+  void afterFile(File file, String label, SourceCode output, {bool changed}) {
     // TODO(rnystrom): Put an empty selection in here to remain compatible with
     // the old formatter. Since there's no way to pass a selection on the
     // command line, this will never be used, which is why it's hard-coded to
@@ -108,7 +114,7 @@
 
 /// Overwrites each file with its formatted result.
 class _OverwriteReporter extends _PrintReporter {
-  void showFile(File file, String label, SourceCode output, {bool changed}) {
+  void afterFile(File file, String label, SourceCode output, {bool changed}) {
     if (changed) {
       file.writeAsStringSync(output.text);
       print("Formatted $label");
@@ -117,3 +123,77 @@
     }
   }
 }
+
+/// A decorating reporter that reports how long it took for format each file.
+class ProfileReporter implements OutputReporter {
+  final OutputReporter _inner;
+
+  /// The files that have been started but have not completed yet.
+  ///
+  /// Maps a file label to the time that it started being formatted.
+  final Map<String, DateTime> _ongoing = {};
+
+  /// The elapsed time it took to format each completed file.
+  final Map<String, Duration> _elapsed = {};
+
+  /// The number of files that completed so fast that they aren't worth
+  /// tracking.
+  int _elided = 0;
+
+  ProfileReporter(this._inner);
+
+  /// Show the times for the slowest files to format.
+  void showProfile() {
+    // Everything should be done.
+    assert(_ongoing.isEmpty);
+
+    var files = _elapsed.keys.toList();
+    files.sort((a, b) => _elapsed[b].compareTo(_elapsed[a]));
+
+    for (var file in files) {
+      print("${_elapsed[file]}: $file");
+    }
+
+    if (_elided >= 1) {
+      var s = _elided > 1 ? 's' : '';
+      print("...$_elided more file$s each took less than 10ms.");
+    }
+  }
+
+  /// Describe the directory whose contents are about to be processed.
+  void showDirectory(String path) {
+    _inner.showDirectory(path);
+  }
+
+  /// Describe the symlink at [path] that wasn't followed.
+  void showSkippedLink(String path) {
+    _inner.showSkippedLink(path);
+  }
+
+  /// Describe the hidden [path] that wasn't processed.
+  void showHiddenPath(String path) {
+    _inner.showHiddenPath(path);
+  }
+
+  /// Called when [file] is about to be formatted.
+  void beforeFile(File file, String label) {
+    _inner.beforeFile(file, label);
+
+    _ongoing[label] = new DateTime.now();
+  }
+
+  /// Describe the processed file at [path] whose formatted result is [output].
+  ///
+  /// If the contents of the file are the same as the formatted output,
+  /// [changed] will be false.
+  void afterFile(File file, String label, SourceCode output, {bool changed}) {
+    var elapsed = new DateTime.now().difference(_ongoing.remove(label));
+    if (elapsed.inMilliseconds >= 10) {
+      _elapsed[label] = elapsed;
+    } else {
+      _elided++;
+    }
+
+    _inner.afterFile(file, label, output, changed: changed);
+  }
+}
diff --git a/packages/dart_style/lib/src/io.dart b/packages/dart_style/lib/src/io.dart
index 765ac3e..51f3805 100644
--- a/packages/dart_style/lib/src/io.dart
+++ b/packages/dart_style/lib/src/io.dart
@@ -22,6 +22,8 @@
   options.reporter.showDirectory(directory.path);
 
   var success = true;
+  var shownHiddenPaths = new Set<String>();
+
   for (var entry in directory.listSync(
       recursive: true, followLinks: options.followLinks)) {
     var relative = p.relative(entry.path, from: directory.path);
@@ -34,8 +36,22 @@
     if (entry is! File || !entry.path.endsWith(".dart")) continue;
 
     // If the path is in a subdirectory starting with ".", ignore it.
-    if (p.split(relative).any((part) => part.startsWith("."))) {
-      options.reporter.showHiddenFile(relative);
+    var parts = p.split(relative);
+    var hiddenIndex;
+    for (var i = 0; i < parts.length; i++) {
+      if (parts[i].startsWith(".")) {
+        hiddenIndex = i;
+        break;
+      }
+    }
+
+    if (hiddenIndex != null) {
+      // Since we'll hide everything inside the directory starting with ".",
+      // show the directory name once instead of once for each file.
+      var hiddenPath = p.joinAll(parts.take(hiddenIndex + 1));
+      if (shownHiddenPaths.add(hiddenPath)) {
+        options.reporter.showHiddenPath(hiddenPath);
+      }
       continue;
     }
 
@@ -51,12 +67,14 @@
 bool processFile(FormatterOptions options, File file, {String label}) {
   if (label == null) label = file.path;
 
-  var formatter = new DartFormatter(pageWidth: options.pageWidth);
+  var formatter =
+      new DartFormatter(indent: options.indent, pageWidth: options.pageWidth);
   try {
     var source = new SourceCode(file.readAsStringSync(), uri: file.path);
+    options.reporter.beforeFile(file, label);
     var output = formatter.formatSource(source);
     options.reporter
-        .showFile(file, label, output, changed: source.text != output.text);
+        .afterFile(file, label, output, changed: source.text != output.text);
     return true;
   } on FormatterException catch (err) {
     var color = Platform.operatingSystem != "windows" &&
diff --git a/packages/dart_style/lib/src/line_splitting/line_splitter.dart b/packages/dart_style/lib/src/line_splitting/line_splitter.dart
index f562ca4..420c509 100644
--- a/packages/dart_style/lib/src/line_splitting/line_splitter.dart
+++ b/packages/dart_style/lib/src/line_splitting/line_splitter.dart
@@ -130,10 +130,10 @@
       int firstLineIndent,
       {bool flushLeft: false})
       : chunks = chunks,
-        // Collect the set of soft rules that we need to select values for.
+        // Collect the set of rules that we need to select values for.
         rules = chunks
             .map((chunk) => chunk.rule)
-            .where((rule) => rule != null && rule is! HardSplitRule)
+            .where((rule) => rule != null)
             .toSet()
             .toList(growable: false),
         blockIndentation = blockIndentation,
@@ -145,6 +145,12 @@
     for (var i = 0; i < rules.length; i++) {
       rules[i].index = i;
     }
+
+    // Now that every used rule has an index, tell the rules to discard any
+    // constraints on unindexed rules.
+    for (var rule in rules) {
+      rule.forgetUnusedRules();
+    }
   }
 
   /// Determine the best way to split the chunks into lines that fit in the
diff --git a/packages/dart_style/lib/src/line_splitting/rule_set.dart b/packages/dart_style/lib/src/line_splitting/rule_set.dart
index 709b373..714875d 100644
--- a/packages/dart_style/lib/src/line_splitting/rule_set.dart
+++ b/packages/dart_style/lib/src/line_splitting/rule_set.dart
@@ -23,14 +23,22 @@
   RuleSet._(this._values);
 
   /// Returns `true` of [rule] is bound in this set.
-  bool contains(Rule rule) => _values[rule.index] != null;
+  bool contains(Rule rule) {
+    // Treat hardened rules as implicitly bound.
+    if (rule.isHardened) return true;
 
-  /// Gets the bound value for [rule] or `0` if it is not bound.
+    return _values[rule.index] != null;
+  }
+
+  /// Gets the bound value for [rule] or [Rule.unsplit] if it is not bound.
   int getValue(Rule rule) {
+    // Hardened rules are implicitly bound.
+    if (rule.isHardened) return rule.fullySplitValue;
+
     var value = _values[rule.index];
     if (value != null) return value;
 
-    return 0;
+    return Rule.unsplit;
   }
 
   /// Invokes [callback] for each rule in [rules] with the rule's value, which
@@ -56,19 +64,26 @@
   /// If an unbound rule gets constrained to `-1` (meaning it must split, but
   /// can split any way it wants), invokes [onSplitRule] with it.
   bool tryBind(List<Rule> rules, Rule rule, int value, onSplitRule(Rule rule)) {
+    assert(!rule.isHardened);
+
     _values[rule.index] = value;
 
     // Test this rule against the other rules being bound.
-    for (var other in rules) {
-      if (rule == other) continue;
+    for (var other in rule.constrainedRules) {
+      var otherValue;
+      // Hardened rules are implicitly bound.
+      if (other.isHardened) {
+        otherValue = other.fullySplitValue;
+      } else {
+        otherValue = _values[other.index];
+      }
 
-      var otherValue = _values[other.index];
       var constraint = rule.constrain(value, other);
 
       if (otherValue == null) {
         // The other rule is unbound, so see if we can constrain it eagerly to
         // a value now.
-        if (constraint == -1) {
+        if (constraint == Rule.mustSplit) {
           // If we know the rule has to split and there's only one way it can,
           // just bind that.
           if (other.numValues == 2) {
@@ -84,16 +99,16 @@
       } else {
         // It's already bound, so see if the new rule's constraint disallows
         // that value.
-        if (constraint == -1) {
-          if (otherValue == 0) return false;
+        if (constraint == Rule.mustSplit) {
+          if (otherValue == Rule.unsplit) return false;
         } else if (constraint != null) {
           if (otherValue != constraint) return false;
         }
 
         // See if the other rule's constraint allows us to use this value.
         constraint = other.constrain(otherValue, rule);
-        if (constraint == -1) {
-          if (value == 0) return false;
+        if (constraint == Rule.mustSplit) {
+          if (value == Rule.unsplit) return false;
         } else if (constraint != null) {
           if (value != constraint) return false;
         }
diff --git a/packages/dart_style/lib/src/line_splitting/solve_state.dart b/packages/dart_style/lib/src/line_splitting/solve_state.dart
index b419756..e1e9168 100644
--- a/packages/dart_style/lib/src/line_splitting/solve_state.dart
+++ b/packages/dart_style/lib/src/line_splitting/solve_state.dart
@@ -6,6 +6,7 @@
 
 import '../debug.dart' as debug;
 import '../rule/rule.dart';
+import '../whitespace.dart';
 import 'line_splitter.dart';
 import 'rule_set.dart';
 
@@ -25,11 +26,21 @@
   final LineSplitter _splitter;
   final RuleSet _ruleValues;
 
+  /// The set of [Rule]s that are bound by [_ruleValues].
+  ///
+  /// Cached by [_ensureConstraints] for use by [_ensureUnboundConstraints].
+  Set<Rule> _boundRules;
+
+  /// The set of [Rule]s that are not bound by [_ruleValues].
+  ///
+  /// Cached by [_ensureConstraints] for use by [_ensureUnboundConstraints].
+  Set<Rule> _unboundRules;
+
   /// The unbound rules in this state that can be bound to produce new more
   /// refined states.
   ///
   /// Keeping this set small is the key to make the entire line splitter
-  /// perform well. If we consider too make rules at each state, our
+  /// perform well. If we consider too many rules at each state, our
   /// exploration of the solution space is too branchy and we waste time on
   /// dead end solutions.
   ///
@@ -75,6 +86,19 @@
   /// unbound rules.
   Map<Rule, int> _constraints;
 
+  /// The unbound rule values that are disallowed because they would place
+  /// invalid constraints on the currently bound values.
+  ///
+  /// For example, say rule A is bound to 1 and B is unbound. If B has value
+  /// 1, it constrains A to be 1. Likewise, if B is 2, it constrains A to be
+  /// 2 as well. Since we already know A is 1, that means we know B cannot be
+  /// bound to value 2. This means B is more limited in this state than it
+  /// might be in another state that binds A to a different value.
+  ///
+  /// It's important to track this, because we can't allow to states to overlap
+  /// if one permits more values for some unbound rule than the other does.
+  Map<Rule, Set<int>> _unboundConstraints;
+
   /// The bound rules that appear inside lines also containing unbound rules.
   ///
   /// By appearing in the same line, it means these bound rules may affect the
@@ -87,13 +111,9 @@
     _calculateCost();
   }
 
-  /// Gets the value to use for [rule], either the bound value or `0` if it
-  /// isn't bound.
-  int getValue(Rule rule) {
-    if (rule is HardSplitRule) return 0;
-
-    return _ruleValues.getValue(rule);
-  }
+  /// Gets the value to use for [rule], either the bound value or
+  /// [Rule.unsplit] if it isn't bound.
+  int getValue(Rule rule) => _ruleValues.getValue(rule);
 
   /// Returns `true` if this state is a better solution to use as the final
   /// result than [other].
@@ -212,11 +232,10 @@
 
   /// Returns `true` if [other] overlaps this state.
   bool _isOverlapping(SolveState other) {
-    _ensureOverlapFields();
-    other._ensureOverlapFields();
-
     // Lines that contain both bound and unbound rules must have the same
     // bound values.
+    _ensureBoundRulesInUnboundLines();
+    other._ensureBoundRulesInUnboundLines();
     if (_boundRulesInUnboundLines.length !=
         other._boundRulesInUnboundLines.length) {
       return false;
@@ -229,12 +248,30 @@
       }
     }
 
+    _ensureConstraints();
+    other._ensureConstraints();
     if (_constraints.length != other._constraints.length) return false;
 
     for (var rule in _constraints.keys) {
       if (_constraints[rule] != other._constraints[rule]) return false;
     }
 
+    _ensureUnboundConstraints();
+    other._ensureUnboundConstraints();
+    if (_unboundConstraints.length != other._unboundConstraints.length) {
+      return false;
+    }
+
+    for (var rule in _unboundConstraints.keys) {
+      var disallowed = _unboundConstraints[rule];
+      var otherDisallowed = other._unboundConstraints[rule];
+
+      if (disallowed.length != otherDisallowed.length) return false;
+      for (var value in disallowed) {
+        if (!otherDisallowed.contains(value)) return false;
+      }
+    }
+
     return true;
   }
 
@@ -267,6 +304,8 @@
 
           // And any expression nesting.
           indent += chunk.nesting.totalUsedIndent;
+
+          if (chunk.indentBlock(getValue)) indent += Indent.expression;
         }
 
         _splits.add(i, indent);
@@ -288,7 +327,8 @@
 
     // The unbound rules in use by the current line. This will be null after
     // the first long line has completed.
-    var currentLineRules = [];
+    var foundOverflowRules = false;
+    var start = 0;
 
     endLine(int end) {
       // Track lines that went over the length. It is only rules contained in
@@ -298,16 +338,16 @@
 
         // Only try rules that are in the first long line, since we know at
         // least one of them *will* be split.
-        if (currentLineRules != null && currentLineRules.isNotEmpty) {
-          _liveRules.addAll(currentLineRules);
-          currentLineRules = null;
-        }
-      } else {
-        // The line fit, so don't keep track of its rules.
-        if (currentLineRules != null) {
-          currentLineRules.clear();
+        if (!foundOverflowRules) {
+          for (var i = start; i < end; i++) {
+            if (_addLiveRules(_splitter.chunks[i].rule)) {
+              foundOverflowRules = true;
+            }
+          }
         }
       }
+
+      start = end;
     }
 
     // The set of spans that contain chunks that ended up splitting. We store
@@ -315,6 +355,9 @@
     // one split occurs in it.
     var splitSpans = new Set();
 
+    // The nesting level of the chunk that ended the previous line.
+    var previousNesting;
+
     for (var i = 0; i < _splitter.chunks.length; i++) {
       var chunk = _splitter.chunks[i];
 
@@ -329,11 +372,37 @@
         splitSpans.addAll(chunk.spans);
 
         // Include the cost of the nested block.
-        if (chunk.blockChunks.isNotEmpty) {
+        if (chunk.isBlock) {
           cost +=
               _splitter.writer.formatBlock(chunk, _splits.getColumn(i)).cost;
         }
 
+        // Do not allow sequential lines to have the same indentation but for
+        // different reasons. In other words, don't allow different expressions
+        // to claim the same nesting level on subsequent lines.
+        //
+        // A contrived example would be:
+        //
+        //     function(inner(
+        //         argument), second(
+        //         another);
+        //
+        // For the most part, we prevent this by the constraints on splits.
+        // For example, the above can't happen because the split before
+        // "argument", forces the split before "second".
+        //
+        // But there are a couple of squirrely cases where it's hard to prevent
+        // by construction. Instead, this outlaws it by penalizing it very
+        // heavily if it happens to get this far.
+        if (previousNesting != null &&
+            chunk.nesting.totalUsedIndent != 0 &&
+            chunk.nesting.totalUsedIndent == previousNesting.totalUsedIndent &&
+            !identical(chunk.nesting, previousNesting)) {
+          _overflowChars += 10000;
+        }
+
+        previousNesting = chunk.nesting;
+
         // Start the new line.
         length = _splits.getColumn(i);
       } else {
@@ -341,23 +410,12 @@
 
         // Include the nested block inline, if any.
         length += chunk.unsplitBlockLength;
-
-        // If we might be in the first overly long line, keep track of any
-        // unbound rules we encounter. These are ones that we'll want to try to
-        // bind to shorten the long line.
-        if (currentLineRules != null &&
-            chunk.rule != null &&
-            !chunk.isHardSplit &&
-            !_ruleValues.contains(chunk.rule)) {
-          currentLineRules.add(chunk.rule);
-        }
       }
     }
 
-    // Add the costs for the rules that split.
+    // Add the costs for the rules that have any splits.
     _ruleValues.forEach(_splitter.rules, (rule, value) {
-      // A rule may be bound to zero if another rule constrains it to not split.
-      if (value != 0) cost += rule.cost;
+      if (value != Rule.unsplit) cost += rule.cost;
     });
 
     // Add the costs for the spans containing splits.
@@ -369,46 +427,32 @@
     _splits.setCost(cost);
   }
 
-  /// Lazily initializes the fields needed to compare two states for overlap.
+  /// Adds [rule] and all of the rules it constrains to the set of [_liveRules].
+  ///
+  /// Only does this if [rule] is a valid soft rule. Returns `true` if any new
+  /// live rules were added.
+  bool _addLiveRules(Rule rule) {
+    if (rule == null) return false;
+
+    var added = false;
+    for (var constrained in rule.allConstrainedRules) {
+      if (_ruleValues.contains(constrained)) continue;
+
+      _liveRules.add(constrained);
+      added = true;
+    }
+
+    return added;
+  }
+
+  /// Lazily initializes the [_boundInUnboundLines], which is needed to compare
+  /// two states for overlap.
   ///
   /// We do this lazily because the calculation is a bit slow, and is only
   /// needed when we have two states with the same score.
-  void _ensureOverlapFields() {
-    if (_constraints != null) return;
+  void _ensureBoundRulesInUnboundLines() {
+    if (_boundRulesInUnboundLines != null) return;
 
-    _calculateConstraints();
-    _calculateBoundRulesInUnboundLines();
-  }
-
-  /// Initializes [_constraints] with any constraints the bound rules place on
-  /// the unbound rules.
-  void _calculateConstraints() {
-    _constraints = {};
-
-    var unboundRules = [];
-    var boundRules = [];
-
-    for (var rule in _splitter.rules) {
-      if (_ruleValues.contains(rule)) {
-        boundRules.add(rule);
-      } else {
-        unboundRules.add(rule);
-      }
-    }
-
-    for (var bound in boundRules) {
-      var value = _ruleValues.getValue(bound);
-
-      for (var unbound in unboundRules) {
-        var constraint = bound.constrain(value, unbound);
-        if (constraint != null) {
-          _constraints[unbound] = constraint;
-        }
-      }
-    }
-  }
-
-  void _calculateBoundRulesInUnboundLines() {
     _boundRulesInUnboundLines = new Set();
 
     var boundInLine = new Set();
@@ -423,7 +467,7 @@
       }
 
       var rule = _splitter.chunks[i].rule;
-      if (rule != null && rule is! HardSplitRule) {
+      if (rule != null) {
         if (_ruleValues.contains(rule)) {
           boundInLine.add(rule);
         } else {
@@ -435,6 +479,89 @@
     if (hasUnbound) _boundRulesInUnboundLines.addAll(boundInLine);
   }
 
+  /// Lazily initializes the [_constraints], which is needed to compare two
+  /// states for overlap.
+  ///
+  /// We do this lazily because the calculation is a bit slow, and is only
+  /// needed when we have two states with the same score.
+  void _ensureConstraints() {
+    if (_constraints != null) return;
+
+    _unboundRules = new Set();
+    _boundRules = new Set();
+
+    for (var rule in _splitter.rules) {
+      if (_ruleValues.contains(rule)) {
+        _boundRules.add(rule);
+      } else {
+        _unboundRules.add(rule);
+      }
+    }
+
+    _constraints = {};
+
+    for (var bound in _boundRules) {
+      for (var unbound in bound.constrainedRules) {
+        if (!_unboundRules.contains(unbound)) continue;
+
+        var value = _ruleValues.getValue(bound);
+        var constraint = bound.constrain(value, unbound);
+        if (constraint != null) {
+          _constraints[unbound] = constraint;
+        }
+      }
+    }
+  }
+
+  /// Lazily initializes the [_unboundConstraints], which is needed to compare
+  /// two states for overlap.
+  ///
+  /// We do this lazily because the calculation is a bit slow, and is only
+  /// needed when we have two states with the same score.
+  void _ensureUnboundConstraints() {
+    if (_unboundConstraints != null) return;
+
+    // _ensureConstraints should be called first which initializes these.
+    assert(_boundRules != null);
+    assert(_unboundRules != null);
+
+    _unboundConstraints = {};
+
+    for (var unbound in _unboundRules) {
+      var disallowedValues;
+
+      for (var bound in unbound.constrainedRules) {
+        if (!_boundRules.contains(bound)) continue;
+
+        var boundValue = _ruleValues.getValue(bound);
+
+        for (var value = 0; value < unbound.numValues; value++) {
+          var constraint = unbound.constrain(value, bound);
+
+          // If the unbound rule doesn't place any constraint on this bound
+          // rule, we're fine.
+          if (constraint == null) continue;
+
+          // If the bound rule's value already meets the constraint it applies,
+          // we don't need to track it. This way, two states that have the
+          // same bound value, one of which has a satisfied constraint, are
+          // still allowed to overlap.
+          if (constraint == boundValue) continue;
+          if (constraint == Rule.mustSplit && boundValue != Rule.unsplit) {
+            continue;
+          }
+
+          if (disallowedValues == null) {
+            disallowedValues = new Set();
+            _unboundConstraints[unbound] = disallowedValues;
+          }
+
+          disallowedValues.add(value);
+        }
+      }
+    }
+  }
+
   String toString() {
     var buffer = new StringBuffer();
 
diff --git a/packages/dart_style/lib/src/line_writer.dart b/packages/dart_style/lib/src/line_writer.dart
index 055892e..9fb5d39 100644
--- a/packages/dart_style/lib/src/line_writer.dart
+++ b/packages/dart_style/lib/src/line_writer.dart
@@ -82,7 +82,7 @@
     if (cached != null) return cached;
 
     var writer = new LineWriter._(
-        chunk.blockChunks, _lineEnding, pageWidth, column, _blockCache);
+        chunk.block.chunks, _lineEnding, pageWidth, column, _blockCache);
 
     // TODO(rnystrom): Passing in an initial indent here is hacky. The
     // LineWriter ensures all but the first chunk have a block indent, and this
@@ -131,7 +131,7 @@
         _buffer.toString(), totalCost, _selectionStart, _selectionEnd);
   }
 
-  /// Takes the first [length] of the chunks with leading [indent], removes
+  /// Takes the chunks from [start] to [end] with leading [indent], removes
   /// them, and runs the [LineSplitter] on them.
   int _completeLine(int newlines, int indent, int start, int end,
       {bool flushLeft}) {
@@ -144,7 +144,7 @@
 
     if (debug.traceLineWriter) {
       debug.log(debug.green("\nWriting:"));
-      debug.dumpChunks(start, chunks);
+      debug.dumpChunks(0, chunks);
       debug.log();
     }
 
@@ -163,11 +163,11 @@
       var chunk = chunks[i];
       _writeChunk(chunk);
 
-      if (chunk.blockChunks.isNotEmpty) {
+      if (chunk.isBlock) {
         if (!splits.shouldSplitAt(i)) {
           // This block didn't split (which implies none of the child blocks
           // of that block split either, recursively), so write them all inline.
-          _writeChunksUnsplit(chunk.blockChunks);
+          _writeChunksUnsplit(chunk);
         } else {
           // Include the formatted block contents.
           var block = formatBlock(chunk, splits.getColumn(i));
@@ -201,16 +201,18 @@
     return splits.cost;
   }
 
-  /// Writes [chunks] (and any child chunks of them, recursively) without any
-  /// splitting.
-  void _writeChunksUnsplit(List<Chunk> chunks) {
-    for (var chunk in chunks) {
-      _writeChunk(chunk);
+  /// Writes the block chunks of [chunk] (and any child chunks of them,
+  /// recursively) without any splitting.
+  void _writeChunksUnsplit(Chunk chunk) {
+    if (!chunk.isBlock) return;
 
-      if (chunk.spaceWhenUnsplit) _buffer.write(" ");
+    for (var blockChunk in chunk.block.chunks) {
+      _writeChunk(blockChunk);
+
+      if (blockChunk.spaceWhenUnsplit) _buffer.write(" ");
 
       // Recurse into the block.
-      _writeChunksUnsplit(chunk.blockChunks);
+      _writeChunksUnsplit(blockChunk);
     }
   }
 
diff --git a/packages/dart_style/lib/src/nesting_builder.dart b/packages/dart_style/lib/src/nesting_builder.dart
index 095f247..2efebb3 100644
--- a/packages/dart_style/lib/src/nesting_builder.dart
+++ b/packages/dart_style/lib/src/nesting_builder.dart
@@ -7,36 +7,25 @@
 import 'nesting_level.dart';
 import 'whitespace.dart';
 
-/// Keeps track of expression nesting while the source code is being visited
-/// and the chunks are being built.
+/// Keeps track of block indentation and expression nesting while the source
+/// code is being visited and the chunks are being built.
+///
+/// This class requires (and verifies) that indentation and nesting are
+/// stratified from each other. Expression nesting is always inside block
+/// indentation, which means it is an error to try to change the block
+/// indentation while any expression nesting is in effect.
 class NestingBuilder {
-  /// The expression nesting levels and block indentation levels.
+  /// The block indentation levels.
   ///
-  /// This is tracked as a stack of [_IndentLevel]s. Each element in the stack
-  /// represents a level of block indentation. It's stored as a stack because
-  /// expressions may contain blocks which in turn contain other expressions.
-  /// The nesting level of the inner expressions are unrelated to the
-  /// surrounding ones. For example:
-  ///
-  ///     outer(invocation(() {
-  ///       inner(lambda());
-  ///     }));
-  ///
-  /// When writing `inner(lambda())`, we need to track its nesting level. At
-  /// the same time, when the lambda is done, we need to return to the nesting
-  /// level of `outer(invocation(...`.
-  // TODO(rnystrom): I think this is no longer true now that blocks are handled
-  // as separate nested chunks. Once cascades use expression nesting, we may
-  // be able to just store a single nesting depth in NestingBuilder.
-  ///
-  /// Has an implicit entry for top-most expression nesting outside of any
-  /// block for things like wrapped directives.
-  final List<_IndentLevel> _stack = [new _IndentLevel(0)];
+  /// This is tracked as a stack of numbers, each of which is the total number
+  /// of spaces of block indentation. We only store the stack of previous
+  /// levels as a convenience to the caller: it spares you from having to pass
+  /// the unindent amount to [unindent()].
+  final List<int> _stack = [0];
 
-  /// When not `null`, the nesting level of the current innermost block after
-  /// the next token is written.
+  /// When not `null`, the expression nesting after the next token is written.
   ///
-  /// When the nesting level is increased, we don't want it to take effect until
+  /// When the nesting is increased, we don't want it to take effect until
   /// after at least one token has been written. That ensures that comments
   /// appearing before the first token are correctly indented. For example, a
   /// binary operator expression increases the nesting before the first operand
@@ -51,24 +40,35 @@
   /// would incorrectly get indented because the line comment adds a split which
   /// would take the nesting level of the binary operator into account even
   /// though we haven't written any of its tokens yet.
+  ///
+  /// Likewise, when nesting is decreased, we may want to defer that until
+  /// we've written the next token to handle uncommon cases like:
+  ///
+  ///     do // comment
+  ///         {
+  ///       ...
+  ///     }
+  ///
+  /// Here, if we discard the expression nesting before we reach the "{", then
+  /// it won't get indented as it should.
   NestingLevel _pendingNesting;
 
   /// The current number of characters of block indentation.
-  int get indentation => _stack.last.indent;
+  int get indentation => _stack.last;
 
-  /// The nesting depth of the current inner-most block.
-  NestingLevel get nesting => _stack.last.nesting;
+  /// The current nesting, ignoring any pending nesting.
+  NestingLevel get nesting => _nesting;
+  NestingLevel _nesting = new NestingLevel();
 
-  /// The nesting depth of the current inner-most block, including any pending
-  /// nesting.
+  /// The current nesting, including any pending nesting.
   NestingLevel get currentNesting =>
-      _pendingNesting != null ? _pendingNesting : _stack.last.nesting;
+      _pendingNesting != null ? _pendingNesting : _nesting;
 
   /// The top "nesting level" that represents no expression nesting for the
   /// current block.
   NestingLevel get blockNesting {
     // Walk the nesting levels until we bottom out.
-    var result = nesting;
+    var result = _nesting;
     while (result.parent != null) {
       result = result.parent;
     }
@@ -81,20 +81,31 @@
   void indent([int spaces]) {
     if (spaces == null) spaces = Indent.block;
 
+    // Indentation should only change outside of nesting.
     assert(_pendingNesting == null);
+    assert(_nesting.indent == 0);
 
-    _stack.add(new _IndentLevel(_stack.last.indent + spaces));
+    _stack.add(_stack.last + spaces);
   }
 
   /// Discards the most recent indentation level.
   void unindent() {
+    // Indentation should only change outside of nesting.
     assert(_pendingNesting == null);
+    assert(_nesting.indent == 0);
+
+    // If this fails, an unindent() call did not have a preceding indent() call.
+    assert(_stack.isNotEmpty);
+
     _stack.removeLast();
   }
 
   /// Begins a new expression nesting level [indent] deeper than the current
   /// one if it splits.
   ///
+  /// Expressions that are more nested will get increased indentation when split
+  /// if the previous line has a lower level of nesting.
+  ///
   /// If [indent] is omitted, defaults to [Indent.expression].
   void nest([int indent]) {
     if (indent == null) indent = Indent.expression;
@@ -102,46 +113,27 @@
     if (_pendingNesting != null) {
       _pendingNesting = _pendingNesting.nest(indent);
     } else {
-      _pendingNesting = nesting.nest(indent);
+      _pendingNesting = _nesting.nest(indent);
     }
   }
 
   /// Discards the most recent level of expression nesting.
-  ///
-  /// Expressions that are more nested will get increased indentation when split
-  /// if the previous line has a lower level of nesting.
   void unnest() {
-    // By the time the nesting is done, it should have emitted some text and
-    // not be pending anymore.
-    assert(_pendingNesting == null);
+    if (_pendingNesting != null) {
+      _pendingNesting = _pendingNesting.parent;
+    } else {
+      _pendingNesting = _nesting.parent;
+    }
 
-    _setNesting(nesting.parent);
+    // If this fails, an unnest() call did not have a preceding nest() call.
+    assert(_pendingNesting != null);
   }
 
   /// Applies any pending nesting now that we are ready for it to take effect.
   void commitNesting() {
     if (_pendingNesting == null) return;
 
-    _setNesting(_pendingNesting);
+    _nesting = _pendingNesting;
     _pendingNesting = null;
   }
-
-  /// Sets the nesting level of the innermost block to [level].
-  void _setNesting(NestingLevel level) {
-    _stack.last.nesting = level;
-  }
-}
-
-/// A level of block nesting.
-///
-/// This represents indentation changes that typically occur at statement or
-/// block boundaries.
-class _IndentLevel {
-  /// The number of spaces of indentation at this level.
-  final int indent;
-
-  /// The current expression nesting in this indentation level.
-  NestingLevel nesting = new NestingLevel();
-
-  _IndentLevel(this.indent);
 }
diff --git a/packages/dart_style/lib/src/rule/argument.dart b/packages/dart_style/lib/src/rule/argument.dart
index 813bfb1..ed7758a 100644
--- a/packages/dart_style/lib/src/rule/argument.dart
+++ b/packages/dart_style/lib/src/rule/argument.dart
@@ -9,8 +9,23 @@
 
 /// Base class for a rule that handles argument or parameter lists.
 abstract class ArgumentRule extends Rule {
+  /// The chunks prior to each positional argument.
+  final List<Chunk> _arguments = [];
+
   /// The rule used to split collections in the argument list, if any.
-  final Rule _collectionRule;
+  Rule _collectionRule;
+
+  /// The number of leading collection arguments.
+  ///
+  /// This and [_trailingCollections] cannot both be positive. If every
+  /// argument is a collection, this will be [_arguments.length] and
+  /// [_trailingCollections] will be 0.
+  final int _leadingCollections;
+
+  /// The number of trailing collections.
+  ///
+  /// This and [_leadingCollections] cannot both be positive.
+  final int _trailingCollections;
 
   /// If true, then inner rules that are written will force this rule to split.
   ///
@@ -21,11 +36,26 @@
   /// Don't split when an inner collection rule splits.
   bool get splitsOnInnerRules => _trackInnerRules;
 
-  /// Creates a new rule for a positional argument list.
-  ///
-  /// If [_collectionRule] is given, it is the rule used to split the
-  /// collections in the list.
-  ArgumentRule(this._collectionRule);
+  ArgumentRule(this._collectionRule, this._leadingCollections,
+      this._trailingCollections);
+
+  void addConstrainedRules(Set<Rule> rules) {
+    super.addConstrainedRules(rules);
+    if (_collectionRule != null) rules.add(_collectionRule);
+  }
+
+  void forgetUnusedRules() {
+    super.forgetUnusedRules();
+    if (_collectionRule != null && _collectionRule.index == null) {
+      _collectionRule = null;
+    }
+  }
+
+  /// Remembers [chunk] as containing the split that occurs right before an
+  /// argument in the list.
+  void beforeArgument(Chunk chunk) {
+    _arguments.add(chunk);
+  }
 
   /// Called before a collection argument is written.
   ///
@@ -46,28 +76,37 @@
 
 /// Base class for a rule for handling positional argument lists.
 abstract class PositionalRule extends ArgumentRule {
-  /// The chunks prior to each positional argument.
-  final List<Chunk> _arguments = [];
-
   /// If there are named arguments following these positional ones, this will
   /// be their rule.
   Rule _namedArgsRule;
 
   /// Creates a new rule for a positional argument list.
   ///
-  /// If [collectionRule] is given, it is the rule used to split the collection
+  /// If [_collectionRule] is given, it is the rule used to split the collection
   /// arguments in the list.
-  PositionalRule(Rule collectionRule) : super(collectionRule);
+  PositionalRule(
+      Rule collectionRule, int leadingCollections, int trailingCollections)
+      : super(collectionRule, leadingCollections, trailingCollections);
 
-  /// Remembers [chunk] as containing the split that occurs right before an
-  /// argument in the list.
-  void beforeArgument(Chunk chunk) {
-    _arguments.add(chunk);
+  void addConstrainedRules(Set<Rule> rules) {
+    super.addConstrainedRules(rules);
+    if (_namedArgsRule != null) rules.add(_namedArgsRule);
   }
 
-  /// Remembers that [rule] is the [NamedArgsRule] immediately following this
+  void forgetUnusedRules() {
+    super.forgetUnusedRules();
+    if (_namedArgsRule != null && _namedArgsRule.index == null) {
+      _namedArgsRule = null;
+    }
+  }
+
+  /// Remembers that [rule] is the [Rule] immediately following this positional
   /// positional argument list.
-  void setNamedArgsRule(NamedRule rule) {
+  ///
+  /// This is normally a [NamedRule] but [PositionalRule] is also used for the
+  /// property accesses at the beginning of a call chain, in which case this
+  /// is just a [SimpleRule].
+  void setNamedArgsRule(Rule rule) {
     _namedArgsRule = rule;
   }
 
@@ -104,20 +143,16 @@
   /// internally without forcing a split before the argument.
   final bool splitsOnInnerRules;
 
-  bool hack = false;
-
   /// Creates a new rule for a positional argument list.
   ///
   /// If [collectionRule] is given, it is the rule used to split the
   /// collections in the list. If [splitsOnInnerRules] is `true`, then we will
   /// split before the argument if the argument itself contains a split.
   SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules})
-      : super(collectionRule),
+      : super(collectionRule, 0, 0),
         splitsOnInnerRules =
             splitsOnInnerRules != null ? splitsOnInnerRules : false;
 
-  bool isSplit(int value, Chunk chunk) => value == 1;
-
   int constrain(int value, Rule other) {
     var constrained = super.constrain(value, other);
     if (constrained != null) return constrained;
@@ -125,10 +160,10 @@
     if (other != _collectionRule) return null;
 
     // If we aren't splitting any args, we can split the collection.
-    if (value == 0) return null;
+    if (value == Rule.unsplit) return null;
 
     // We are splitting before a collection, so don't let it split internally.
-    return 0;
+    return Rule.unsplit;
   }
 
   String toString() => "1Pos${super.toString()}";
@@ -152,18 +187,6 @@
 /// splits before all of the non-collection arguments, but does not split
 /// before the collections, so that they can split internally.
 class MultiplePositionalRule extends PositionalRule {
-  /// The number of leading collection arguments.
-  ///
-  /// This and [_trailingCollections] cannot both be positive. If every
-  /// argument is a collection, this will be [_arguments.length] and
-  /// [_trailingCollections] will be 0.
-  final int _leadingCollections;
-
-  /// The number of trailing collections.
-  ///
-  /// This and [_leadingCollections] cannot both be positive.
-  final int _trailingCollections;
-
   int get numValues {
     // Can split before any one argument, none, or all.
     var result = 2 + _arguments.length;
@@ -181,15 +204,12 @@
   }
 
   MultiplePositionalRule(
-      Rule collectionRule, this._leadingCollections, this._trailingCollections)
-      : super(collectionRule);
+      Rule collectionRule, int leadingCollections, int trailingCollections)
+      : super(collectionRule, leadingCollections, trailingCollections);
 
   String toString() => "*Pos${super.toString()}";
 
-  bool isSplit(int value, Chunk chunk) {
-    // Don't split at all.
-    if (value == 0) return false;
-
+  bool isSplitAtValue(int value, Chunk chunk) {
     // Split only before the first argument. Keep the entire argument list
     // together on the next line.
     if (value == 1) return chunk == _arguments.first;
@@ -224,17 +244,22 @@
     var constrained = super.constrain(value, other);
     if (constrained != null) return constrained;
 
+    // Decide how to constrain the collection rule.
     if (other != _collectionRule) return null;
 
+    // If all of the collections are in the named arguments, [_collectionRule]
+    // will not be null, but we don't have to handle it.
+    if (_leadingCollections == 0 && _trailingCollections == 0) return null;
+
     // If we aren't splitting any args, we can split the collection.
-    if (value == 0) return null;
+    if (value == Rule.unsplit) return null;
 
     // Split only before the first argument.
     if (value == 1) {
       if (_leadingCollections > 0) {
         // We are splitting before a collection, so don't let it split
         // internally.
-        return 0;
+        return Rule.unsplit;
       } else {
         // The split is outside of the collections so they can split or not.
         return null;
@@ -245,8 +270,10 @@
     // arguments, don't allow them to split.
     if (value <= _arguments.length) {
       var argument = _arguments.length - value + 1;
-      if (argument < _leadingCollections) return 0;
-      if (argument >= _arguments.length - _trailingCollections) return 0;
+      if (argument < _leadingCollections ||
+          argument >= _arguments.length - _trailingCollections) {
+        return Rule.unsplit;
+      }
 
       return null;
     }
@@ -255,55 +282,53 @@
     // play when we do want to split the collection, so force that here.
     if (value == _arguments.length + 1) return 1;
 
-    // Split before all of the arguments, even the collection, so don't let
-    // them split.
-    return 0;
+    // Split before all of the arguments, even the collections. We'll allow
+    // them to split but indent their bodies if they do.
+    return null;
   }
 }
 
 /// Splitting rule for a list of named arguments or parameters. Its values mean:
 ///
-/// * 0: Do not split at all.
-/// * 1: Split only before first argument.
-/// * 2: Split before all arguments, including the first.
+/// * Do not split at all.
+/// * Split only before first argument.
+/// * Split before all arguments.
 class NamedRule extends ArgumentRule {
-  /// The chunk prior to the first named argument.
-  Chunk _first;
-
   int get numValues => 3;
 
-  NamedRule(Rule collectionRule) : super(collectionRule);
+  NamedRule(
+      Rule collectionRule, int leadingCollections, int trailingCollections)
+      : super(collectionRule, leadingCollections, trailingCollections);
 
-  void beforeArguments(Chunk chunk) {
-    assert(_first == null);
-    _first = chunk;
-  }
+  bool isSplitAtValue(int value, Chunk chunk) {
+    // Move all arguments to the second line as a unit.
+    if (value == 1) return chunk == _arguments.first;
 
-  bool isSplit(int value, Chunk chunk) {
-    switch (value) {
-      case 0:
-        return false;
-      case 1:
-        return chunk == _first;
-      case 2:
-        return true;
-    }
-
-    throw "unreachable";
+    // Otherwise, split before all arguments.
+    return true;
   }
 
   int constrain(int value, Rule other) {
     var constrained = super.constrain(value, other);
     if (constrained != null) return constrained;
 
+    // Decide how to constrain the collection rule.
     if (other != _collectionRule) return null;
 
-    // If we aren't splitting any args, we can split the collection.
-    if (value == 0) return null;
+    // If all of the collections are in the named arguments, [_collectionRule]
+    // will not be null, but we don't have to handle it.
+    if (_leadingCollections == 0 && _trailingCollections == 0) return null;
 
-    // Split before all of the arguments, even the collections, so don't let
-    // them split.
-    return 0;
+    // If we aren't splitting any args, we can split the collection.
+    if (value == Rule.unsplit) return null;
+
+    // Split only before the first argument. Don't allow the collections to
+    // split.
+    if (value == 1) return Rule.unsplit;
+
+    // Split before all of the arguments, even the collections. We'll allow
+    // them to split but indent their bodies if they do.
+    return null;
   }
 
   String toString() => "Named${super.toString()}";
diff --git a/packages/dart_style/lib/src/rule/combinator.dart b/packages/dart_style/lib/src/rule/combinator.dart
index 62ddfdb..1d73031 100644
--- a/packages/dart_style/lib/src/rule/combinator.dart
+++ b/packages/dart_style/lib/src/rule/combinator.dart
@@ -80,12 +80,8 @@
     _names.last.add(chunk);
   }
 
-  bool isSplit(int value, Chunk chunk) {
+  bool isSplitAtValue(int value, Chunk chunk) {
     switch (value) {
-      case 0:
-        // Don't split at all.
-        return false;
-
       case 1:
         // Just split at the combinators.
         return _combinators.contains(chunk);
@@ -106,11 +102,9 @@
         // Split everything.
         return true;
 
-      case 4:
+      default:
         return true;
     }
-
-    throw "unreachable";
   }
 
   /// Returns `true` if [chunk] is for a combinator or a name in the
diff --git a/packages/dart_style/lib/src/rule/metadata.dart b/packages/dart_style/lib/src/rule/metadata.dart
new file mode 100644
index 0000000..9abbe8f
--- /dev/null
+++ b/packages/dart_style/lib/src/rule/metadata.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart_style.src.rule.metadata;
+
+import 'argument.dart';
+import 'rule.dart';
+
+/// Rule for handling splits between parameter metadata annotations and the
+/// following parameter.
+///
+/// Metadata annotations for parameters (and type parameters) get some special
+/// handling. We use a single rule for all annotations in the parameter list.
+/// If any of the annotations split, they all do.
+///
+/// Also, if the annotations split, we force the entire parameter list to fully
+/// split, both named and positional.
+class MetadataRule extends Rule {
+  Rule _positionalRule;
+  Rule _namedRule;
+
+  /// Remembers that [rule] is the [PositionalRule] used by the argument list
+  /// containing the parameter metadata using this rule.
+  void bindPositionalRule(PositionalRule rule) {
+    _positionalRule = rule;
+  }
+
+  /// Remembers that [rule] is the [NamedRule] used by the argument list
+  /// containing the parameter metadata using this rule.
+  void bindNamedRule(NamedRule rule) {
+    _namedRule = rule;
+  }
+
+  /// Constrains the surrounding argument list rules to fully split if the
+  /// metadata does.
+  int constrain(int value, Rule other) {
+    var constrained = super.constrain(value, other);
+    if (constrained != null) return constrained;
+
+    // If the metadata doesn't split, we don't care what the arguments do.
+    if (value == Rule.unsplit) return null;
+
+    // Otherwise, they have to split.
+    if (other == _positionalRule) return _positionalRule.fullySplitValue;
+    if (other == _namedRule) return _namedRule.fullySplitValue;
+
+    return null;
+  }
+
+  void addConstrainedRules(Set<Rule> rules) {
+    if (_positionalRule != null) rules.add(_positionalRule);
+    if (_namedRule != null) rules.add(_namedRule);
+  }
+
+  void forgetUnusedRules() {
+    super.forgetUnusedRules();
+    if (_positionalRule != null && _positionalRule.index == null) {
+      _positionalRule = null;
+    }
+
+    if (_namedRule != null && _namedRule.index == null) {
+      _namedRule = null;
+    }
+  }
+}
diff --git a/packages/dart_style/lib/src/rule/rule.dart b/packages/dart_style/lib/src/rule/rule.dart
index 43a7f6a..e01d3b0 100644
--- a/packages/dart_style/lib/src/rule/rule.dart
+++ b/packages/dart_style/lib/src/rule/rule.dart
@@ -9,26 +9,43 @@
 
 /// A constraint that determines the different ways a related set of chunks may
 /// be split.
-abstract class Rule extends FastHash {
+class Rule extends FastHash {
+  /// Rule value that splits no chunks.
+  ///
+  /// Every rule is required to treat this value as fully unsplit.
+  static const unsplit = 0;
+
+  /// Rule constraint value that means "any value as long as something splits".
+  ///
+  /// It disallows [unsplit] but allows any other value.
+  static const mustSplit = -1;
+
   /// The number of different states this rule can be in.
   ///
   /// Each state determines which set of chunks using this rule are split and
   /// which aren't. Values range from zero to one minus this. Value zero
   /// always means "no chunks are split" and increasing values by convention
   /// mean increasingly undesirable splits.
-  int get numValues;
+  ///
+  /// By default, a rule has two values: fully unsplit and fully split.
+  int get numValues => 2;
 
   /// The rule value that forces this rule into its maximally split state.
   ///
   /// By convention, this is the highest of the range of allowed values.
   int get fullySplitValue => numValues - 1;
 
-  int get cost => Cost.normal;
+  final int cost;
 
   /// During line splitting [LineSplitter] sets this to the index of this
   /// rule in its list of rules.
   int index;
 
+  /// If `true`, the rule has been "hardened" meaning it's been placed into a
+  /// permanent "must fully split" state.
+  bool get isHardened => _isHardened;
+  bool _isHardened = false;
+
   /// The other [Rule]s that "surround" this one (and care about that fact).
   ///
   /// In many cases, if a split occurs inside an expression, surrounding rules
@@ -41,7 +58,6 @@
   ///
   /// This contains all direct as well as transitive relationships. If A
   /// contains B which contains C, C's outerRules contains both B and A.
-  Iterable<Rule> get outerRules => _outerRules;
   final Set<Rule> _outerRules = new Set<Rule>();
 
   /// Adds [inner] as an inner rule of this rule if it cares about inner rules.
@@ -60,7 +76,38 @@
   /// rules.
   bool get splitsOnInnerRules => true;
 
-  bool isSplit(int value, Chunk chunk);
+  Rule([int cost]) : cost = cost ?? Cost.normal;
+
+  /// Creates a new rule that is already fully split.
+  Rule.hard() : cost = 0 {
+    // Set the cost to zero since it will always be applied, so there's no
+    // point in penalizing it.
+    //
+    // Also, this avoids doubled counting in literal blocks where there is both
+    // a split in the outer chunk containing the block and the inner hard split
+    // between the elements or statements.
+    harden();
+  }
+
+  /// Fixes this rule into a "fully split" state.
+  void harden() {
+    _isHardened = true;
+  }
+
+  /// Returns `true` if [chunk] should split when this rule has [value].
+  bool isSplit(int value, Chunk chunk) {
+    if (_isHardened) return true;
+
+    if (value == Rule.unsplit) return false;
+
+    // Let the subclass decide.
+    return isSplitAtValue(value, chunk);
+  }
+
+  /// Subclasses can override this to determine which values split which chunks.
+  ///
+  /// By default, this assumes every chunk splits.
+  bool isSplitAtValue(value, chunk) => true;
 
   /// Given that this rule has [value], determine if [other]'s value should be
   /// constrained.
@@ -70,51 +117,70 @@
   /// value. Returns -1 to allow [other] to take any non-zero value. Returns
   /// null to not constrain other.
   int constrain(int value, Rule other) {
-    // By default, any implied rule will be fully split if this one is fully
-    // split.
-    if (value == 0) return null;
+    // By default, any containing rule will be fully split if this one is split.
+    if (value == Rule.unsplit) return null;
     if (_outerRules.contains(other)) return other.fullySplitValue;
 
     return null;
   }
 
-  String toString() => "$id";
-}
-
-/// A rule that always splits a chunk.
-class HardSplitRule extends Rule {
-  int get numValues => 1;
-
-  /// It's always going to be applied, so there's no point in penalizing it.
+  /// A protected method for subclasses to add the rules that they constrain
+  /// to [rules].
   ///
-  /// Also, this avoids doubled counting in literal blocks where there is both
-  /// a split in the outer chunk containing the block and the inner hard split
-  /// between the elements or statements.
-  int get cost => 0;
+  /// Called by [Rule] the first time [constrainedRules] is accessed.
+  void addConstrainedRules(Set<Rule> rules) {}
 
-  /// It's always split anyway.
-  bool get splitsOnInnerRules => false;
+  /// Discards constraints on any rule that doesn't have an index.
+  ///
+  /// This is called by [LineSplitter] after it has indexed all of the in-use
+  /// rules. A rule may end up with a constraint on a rule that's no longer
+  /// used by any chunk. This can happen if the rule gets hardened, or if it
+  /// simply never got used by a chunk. For example, a rule for splitting an
+  /// empty list of metadata annotations.
+  ///
+  /// This removes all of those.
+  void forgetUnusedRules() {
+    _outerRules.retainWhere((rule) => rule.index != null);
 
-  bool isSplit(int value, Chunk chunk) => true;
+    // Clear the cached ones too.
+    _constrainedRules = null;
+    _allConstrainedRules = null;
+  }
 
-  String toString() => "Hard";
-}
+  /// The other [Rule]s that this rule places immediate constraints on.
+  Set<Rule> get constrainedRules {
+    // Lazy initialize this on first use. Note: Assumes this is only called
+    // after the chunks have been written and any constraints have been wired
+    // up.
+    if (_constrainedRules == null) {
+      _constrainedRules = _outerRules.toSet();
+      addConstrainedRules(_constrainedRules);
+    }
 
-/// A basic rule that has two states: unsplit or split.
-class SimpleRule extends Rule {
-  /// Two values: 0 is unsplit, 1 is split.
-  int get numValues => 2;
+    return _constrainedRules;
+  }
 
-  final int cost;
+  Set<Rule> _constrainedRules;
 
-  final bool splitsOnInnerRules;
+  /// The transitive closure of all of the rules this rule places constraints
+  /// on, directly or indirectly, including itself.
+  Set<Rule> get allConstrainedRules {
+    if (_allConstrainedRules == null) {
+      visit(Rule rule) {
+        if (_allConstrainedRules.contains(rule)) return;
 
-  SimpleRule({int cost, bool splitsOnInnerRules})
-      : cost = cost != null ? cost : Cost.normal,
-        splitsOnInnerRules =
-            splitsOnInnerRules != null ? splitsOnInnerRules : true;
+        _allConstrainedRules.add(rule);
+        rule.constrainedRules.forEach(visit);
+      }
 
-  bool isSplit(int value, Chunk chunk) => value == 1;
+      _allConstrainedRules = new Set();
+      visit(this);
+    }
 
-  String toString() => "Simple${super.toString()}";
+    return _allConstrainedRules;
+  }
+
+  Set<Rule> _allConstrainedRules;
+
+  String toString() => "$id";
 }
diff --git a/packages/dart_style/lib/src/rule/type_argument.dart b/packages/dart_style/lib/src/rule/type_argument.dart
index ebac6c8..8fcc117 100644
--- a/packages/dart_style/lib/src/rule/type_argument.dart
+++ b/packages/dart_style/lib/src/rule/type_argument.dart
@@ -43,7 +43,7 @@
 
   bool isSplit(int value, Chunk chunk) {
     // Don't split at all.
-    if (value == 0) return false;
+    if (value == Rule.unsplit) return false;
 
     // Split before every argument.
     if (value == numValues - 1) return true;
@@ -52,4 +52,6 @@
     // to try to keep as much on the first line as possible.
     return chunk == _arguments[_arguments.length - value];
   }
+
+  String toString() => "TypeArg${super.toString()}";
 }
diff --git a/packages/dart_style/lib/src/source_visitor.dart b/packages/dart_style/lib/src/source_visitor.dart
index 524db2e..a34b367 100644
--- a/packages/dart_style/lib/src/source_visitor.dart
+++ b/packages/dart_style/lib/src/source_visitor.dart
@@ -15,6 +15,7 @@
 import 'dart_formatter.dart';
 import 'rule/argument.dart';
 import 'rule/combinator.dart';
+import 'rule/metadata.dart';
 import 'rule/rule.dart';
 import 'rule/type_argument.dart';
 import 'source_code.dart';
@@ -47,15 +48,6 @@
   /// This is calculated and cached by [_findSelectionEnd].
   int _selectionEnd;
 
-  /// The rule that should be used for the contents of a literal body that are
-  /// about to be written.
-  ///
-  /// This is set by [visitArgumentList] to ensure that all block arguments
-  /// share a rule.
-  ///
-  /// If `null`, a literal body creates its own rule.
-  Rule _nextLiteralBodyRule;
-
   /// A stack that tracks forcing nested collections to split.
   ///
   /// Each entry corresponds to a collection currently being visited and the
@@ -68,6 +60,29 @@
   /// split.
   final List<bool> _collectionSplits = [];
 
+  /// The stack of current rules for handling parameter metadata.
+  ///
+  /// Each time a parameter (or type parameter) list is begun, a single rule
+  /// for all of the metadata annotations on parameters in that list is pushed
+  /// onto this stack. We reuse this rule for all annotations so that they split
+  /// in unison.
+  final List<MetadataRule> _metadataRules = [];
+
+  /// The mapping for collection literals that are managed by the argument
+  /// list that contains them.
+  ///
+  /// When a collection literal appears inside an [ArgumentSublist], the
+  /// argument list provides a rule for the body to split to ensure that all
+  /// collections split in unison. It also tracks the chunk before the
+  /// argument that determines whether or not the collection body is indented
+  /// like an expression or a statement.
+  ///
+  /// Before a collection literal argument is visited, [ArgumentSublist] binds
+  /// itself to the left bracket token of each collection literal it controls.
+  /// When we later visit that literal, we use the token to find that
+  /// association.
+  final Map<Token, ArgumentSublist> _collectionArgumentLists = {};
+
   /// Initialize a newly created visitor to write source code representing
   /// the visited nodes to the given [writer].
   SourceVisitor(this._formatter, this._lineInfo, this._source) {
@@ -170,7 +185,17 @@
 
   visitBinaryExpression(BinaryExpression node) {
     builder.startSpan();
-    builder.nestExpression();
+
+    // If a binary operator sequence appears immediately after a `=>`, don't
+    // add an extra level of nesting. Instead, let the subsequent operands line
+    // up with the first, as in:
+    //
+    //     method() =>
+    //         argument &&
+    //         argument &&
+    //         argument;
+    var isArrowBody = node.parent is ExpressionFunctionBody;
+    if (!isArrowBody) builder.nestExpression();
 
     // Start lazily so we don't force the operator to split if a line comment
     // appears before the first operand.
@@ -202,12 +227,20 @@
 
     builder.endBlockArgumentNesting();
 
-    builder.unnest();
+    if (!isArrowBody) builder.unnest();
     builder.endSpan();
     builder.endRule();
   }
 
   visitBlock(Block node) {
+    // Don't allow splitting in an empty block.
+    if (node.statements.isEmpty &&
+        node.rightBracket.precedingComments == null) {
+      token(node.leftBracket);
+      token(node.rightBracket);
+      return;
+    }
+
     // For a block that is not a function body, just bump the indentation and
     // keep it in the current block.
     if (node.parent is! BlockFunctionBody) {
@@ -284,7 +317,7 @@
       visitNodes(node.cascadeSections, between: zeroSplit);
       builder.endRule();
     } else {
-      builder.startRule(new HardSplitRule());
+      builder.startRule(new Rule.hard());
       zeroSplit();
       visitNodes(node.cascadeSections, between: zeroSplit);
       builder.endRule();
@@ -515,10 +548,15 @@
     // ":" if the parameters and initialization list don't all fit on one line.
     builder.startRule();
 
+    // If the redirecting constructor happens to wrap, we want to make sure
+    // the parameter list gets more deeply indented.
+    if (node.redirectedConstructor != null) builder.nestExpression();
+
     _visitBody(node.parameters, node.body, () {
       // Check for redirects or initializer lists.
       if (node.redirectedConstructor != null) {
         _visitConstructorRedirects(node);
+        builder.unnest();
       } else if (node.initializers.isNotEmpty) {
         _visitConstructorInitializers(node);
       }
@@ -526,7 +564,8 @@
   }
 
   void _visitConstructorRedirects(ConstructorDeclaration node) {
-    token(node.separator /* = */, before: space, after: space);
+    token(node.separator /* = */, before: space);
+    soloSplit();
     visitCommaSeparatedNodes(node.initializers);
     visit(node.redirectedConstructor);
   }
@@ -600,7 +639,7 @@
       if (node.separator.type == TokenType.EQ) space();
       token(node.separator);
 
-      soloSplit(Cost.assignment);
+      soloSplit(_assignmentCost(node.defaultValue));
       visit(node.defaultValue);
 
       builder.unnest();
@@ -609,18 +648,22 @@
   }
 
   visitDoStatement(DoStatement node) {
-    _simpleStatement(node, () {
-      token(node.doKeyword);
-      space();
-      visit(node.body);
-      space();
-      token(node.whileKeyword);
-      space();
-      token(node.leftParenthesis);
-      soloZeroSplit();
-      visit(node.condition);
-      token(node.rightParenthesis);
-    });
+    builder.nestExpression();
+    token(node.doKeyword);
+    space();
+    builder.unnest(now: false);
+    visit(node.body);
+
+    builder.nestExpression();
+    space();
+    token(node.whileKeyword);
+    space();
+    token(node.leftParenthesis);
+    soloZeroSplit();
+    visit(node.condition);
+    token(node.rightParenthesis);
+    token(node.semicolon);
+    builder.unnest();
   }
 
   visitDoubleLiteral(DoubleLiteral node) {
@@ -682,7 +725,10 @@
     // Split after the "=>", using the rule created before the parameters
     // by _visitBody().
     split();
-    builder.endRule();
+
+    // If the body is a binary operator expression, then we want to force the
+    // split at `=>` if the operators split. See visitBinaryExpression().
+    if (node.expression is! BinaryExpression) builder.endRule();
 
     if (_isInLambda(node)) builder.endSpan();
 
@@ -692,6 +738,8 @@
     builder.endSpan();
     builder.endBlockArgumentNesting();
 
+    if (node.expression is BinaryExpression) builder.endRule();
+
     token(node.semicolon);
   }
 
@@ -744,9 +792,9 @@
     space();
     visit(node.iterable);
     token(node.rightParenthesis);
-    space();
-    visit(node.body);
-    builder.unnest();
+    builder.unnest(now: false);
+
+    _visitLoopBody(node.body);
   }
 
   visitFormalParameterList(FormalParameterList node) {
@@ -771,6 +819,8 @@
     builder.nestExpression();
     token(node.leftParenthesis);
 
+    _metadataRules.add(new MetadataRule());
+
     var rule;
     if (requiredParams.isNotEmpty) {
       if (requiredParams.length > 1) {
@@ -779,6 +829,8 @@
         rule = new SinglePositionalRule(null);
       }
 
+      _metadataRules.last.bindPositionalRule(rule);
+
       builder.startRule(rule);
       if (_isInLambda(node)) {
         // Don't allow splitting before the first argument (i.e. right after
@@ -806,13 +858,17 @@
     }
 
     if (optionalParams.isNotEmpty) {
-      var namedRule = new NamedRule(null);
+      var namedRule = new NamedRule(null, 0, 0);
       if (rule != null) rule.setNamedArgsRule(namedRule);
 
+      _metadataRules.last.bindNamedRule(namedRule);
+
       builder.startRule(namedRule);
 
-      namedRule
-          .beforeArguments(builder.split(space: requiredParams.isNotEmpty));
+      // Make sure multi-line default values are indented.
+      builder.startBlockArgumentNesting();
+
+      namedRule.beforeArgument(builder.split(space: requiredParams.isNotEmpty));
 
       // "[" or "{" for optional parameters.
       token(node.leftDelimiter);
@@ -822,15 +878,18 @@
 
         // Write the trailing comma.
         if (param != node.parameters.last) token(param.endToken.next);
-        if (param != optionalParams.last) split();
+        if (param != optionalParams.last) namedRule.beforeArgument(split());
       }
 
+      builder.endBlockArgumentNesting();
       builder.endRule();
 
       // "]" or "}" for optional parameters.
       token(node.rightDelimiter);
     }
 
+    _metadataRules.removeLast();
+
     token(node.rightParenthesis);
     builder.unnest();
   }
@@ -847,9 +906,9 @@
     if (node.initialization != null) {
       visit(node.initialization);
     } else if (node.variables != null) {
-      // Indent split variables more so they aren't at the same level
+      // Nest split variables more so they aren't at the same level
       // as the rest of the loop clauses.
-      builder.indent(Indent.loopVariable);
+      builder.nestExpression();
 
       // Allow the variables to stay unsplit even if the clauses split.
       builder.startRule();
@@ -864,7 +923,7 @@
       });
 
       builder.endRule();
-      builder.unindent();
+      builder.unnest();
     }
 
     token(node.leftSeparator);
@@ -890,21 +949,11 @@
     builder.endRule();
     builder.unnest();
 
-    // The body.
-    if (node.body is! EmptyStatement) space();
-    visit(node.body);
+    _visitLoopBody(node.body);
   }
 
   visitFunctionDeclaration(FunctionDeclaration node) {
-    visitMemberMetadata(node.metadata);
-
-    builder.nestExpression();
-    modifier(node.externalKeyword);
-    visit(node.returnType, after: space);
-    modifier(node.propertyKeyword);
-    visit(node.name);
-    visit(node.functionExpression);
-    builder.unnest();
+    _visitMemberDeclaration(node, node.functionExpression);
   }
 
   visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
@@ -956,10 +1005,35 @@
     token(node.leftParenthesis);
     visit(node.condition);
     token(node.rightParenthesis);
+    builder.unnest(now: false);
 
-    space();
-    visit(node.thenStatement);
-    builder.unnest();
+    visitClause(Statement clause) {
+      if (clause is Block || clause is IfStatement) {
+        space();
+        visit(clause);
+      } else {
+        // Allow splitting in an expression-bodied if even though it's against
+        // the style guide. Since we can't fix the code itself to follow the
+        // style guide, we should at least format it as well as we can.
+        builder.nestExpression(indent: 2, now: true);
+        builder.startRule();
+
+        // If there is an else clause, always split before both the then and
+        // else statements.
+        if (node.elseStatement != null) {
+          builder.writeWhitespace(Whitespace.nestedNewline);
+        } else {
+          split();
+        }
+
+        visit(clause);
+
+        builder.endRule();
+        builder.unnest();
+      }
+    }
+
+    visitClause(node.thenStatement);
 
     if (node.elseStatement != null) {
       if (node.thenStatement is Block) {
@@ -972,8 +1046,7 @@
       }
 
       token(node.elseKeyword);
-      space();
-      visit(node.elseStatement);
+      visitClause(node.elseStatement);
     }
   }
 
@@ -1012,8 +1085,18 @@
       visit(node.target);
     }
 
+    finishIndexExpression(node);
+
+    builder.unnest();
+  }
+
+  /// Visit the index part of [node], excluding the target.
+  ///
+  /// Called by [CallChainVisitor] to handle index expressions in the middle of
+  /// call chains.
+  void finishIndexExpression(IndexExpression node) {
     if (node.target is IndexExpression) {
-      // Corner case: On a chain of [] accesses, allow splitting between them.
+      // Edge case: On a chain of [] accesses, allow splitting between them.
       // Produces nicer output in cases like:
       //
       //     someJson['property']['property']['property']['property']...
@@ -1026,14 +1109,15 @@
     visit(node.index);
     token(node.rightBracket);
     builder.endSpan();
-    builder.unnest();
   }
 
   visitInstanceCreationExpression(InstanceCreationExpression node) {
     builder.startSpan();
     token(node.keyword);
     space();
+    builder.startSpan(Cost.constructorName);
     visit(node.constructorName);
+    builder.endSpan();
     visit(node.argumentList);
     builder.endSpan();
   }
@@ -1112,16 +1196,7 @@
   }
 
   visitMethodDeclaration(MethodDeclaration node) {
-    visitMemberMetadata(node.metadata);
-
-    modifier(node.externalKeyword);
-    modifier(node.modifierKeyword);
-    visit(node.returnType, after: space);
-    modifier(node.propertyKeyword);
-    modifier(node.operatorKeyword);
-    visit(node.name);
-
-    _visitBody(node.parameters, node.body);
+    _visitMemberDeclaration(node, node);
   }
 
   visitMethodInvocation(MethodInvocation node) {
@@ -1149,7 +1224,16 @@
     builder.nestExpression();
     builder.startSpan();
     visit(node.name);
-    visit(node.expression, before: soloSplit);
+
+    // Don't allow a split between a name and a collection. Instead, we want
+    // the collection itself to split, or to split before the argument.
+    if (node.expression is ListLiteral || node.expression is MapLiteral) {
+      space();
+    } else {
+      soloSplit();
+    }
+
+    visit(node.expression);
     builder.endSpan();
     builder.unnest();
   }
@@ -1184,6 +1268,8 @@
   }
 
   visitPartDirective(PartDirective node) {
+    visitDeclarationMetadata(node.metadata);
+
     _simpleStatement(node, () {
       token(node.keyword);
       space();
@@ -1192,6 +1278,8 @@
   }
 
   visitPartOfDirective(PartOfDirective node) {
+    visitDeclarationMetadata(node.metadata);
+
     _simpleStatement(node, () {
       token(node.keyword);
       space();
@@ -1207,9 +1295,7 @@
   }
 
   visitPrefixedIdentifier(PrefixedIdentifier node) {
-    visit(node.prefix);
-    token(node.period);
-    visit(node.identifier);
+    new CallChainVisitor(this, node).visit();
   }
 
   visitPrefixExpression(PrefixExpression node) {
@@ -1357,6 +1443,7 @@
     token(node.rightParenthesis);
     space();
     token(node.leftBracket);
+    builder.unnest();
     builder.indent();
     newline();
 
@@ -1365,7 +1452,6 @@
       builder.unindent();
       newline();
     });
-    builder.unnest();
   }
 
   visitSymbolLiteral(SymbolLiteral node) {
@@ -1425,7 +1511,11 @@
   }
 
   visitTypeParameterList(TypeParameterList node) {
+    _metadataRules.add(new MetadataRule());
+
     _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters);
+
+    _metadataRules.removeLast();
   }
 
   visitVariableDeclaration(VariableDeclaration node) {
@@ -1437,8 +1527,14 @@
 
   visitVariableDeclarationList(VariableDeclarationList node) {
     visitDeclarationMetadata(node.metadata);
+
+    // Allow but try to avoid splitting between the type and name.
+    builder.startSpan();
+
     modifier(node.keyword);
-    visit(node.type, after: space);
+    visit(node.type, after: soloSplit);
+
+    builder.endSpan();
 
     // Use a single rule for all of the variables. If there are multiple
     // declarations, we will try to keep them all on one line. If that isn't
@@ -1463,9 +1559,9 @@
     soloZeroSplit();
     visit(node.condition);
     token(node.rightParenthesis);
-    if (node.body is! EmptyStatement) space();
-    visit(node.body);
-    builder.unnest();
+    builder.unnest(now: false);
+
+    _visitLoopBody(node.body);
   }
 
   visitWithClause(WithClause node) {
@@ -1524,11 +1620,29 @@
   /// These are always on the same line as the parameter.
   void visitParameterMetadata(
       NodeList<Annotation> metadata, void visitParameter()) {
+    if (metadata == null || metadata.isEmpty) {
+      visitParameter();
+      return;
+    }
+
     // Split before all of the annotations or none.
-    builder.startRule();
-    visitNodes(metadata, between: split, after: split);
+    builder.startLazyRule(_metadataRules.last);
+
+    visitNodes(metadata, between: split, after: () {
+      // Don't nest until right before the last metadata. Ensures we only
+      // indent the parameter and not any of the metadata:
+      //
+      //     function(
+      //         @LongAnnotation
+      //         @LongAnnotation
+      //             indentedParameter) {}
+      builder.nestExpression(now: true);
+      split();
+    });
     visitParameter();
 
+    builder.unnest();
+
     // Wrap the rule around the parameter too. If it splits, we want to force
     // the annotations to split as well.
     builder.endRule();
@@ -1543,7 +1657,7 @@
   void _visitAssignment(Token equalsOperator, Expression rightHandSide) {
     space();
     token(equalsOperator);
-    soloSplit(Cost.assignment);
+    soloSplit(_assignmentCost(rightHandSide));
     builder.startSpan();
     visit(rightHandSide);
     builder.endSpan();
@@ -1577,6 +1691,37 @@
     builder.endRule();
   }
 
+  /// Visits a top-level function or method declaration.
+  ///
+  /// The two AST node types are very similar but, alas, share no common
+  /// interface type in analyzer, hence the dynamic typing.
+  void _visitMemberDeclaration(
+      /* FunctionDeclaration|MethodDeclaration */ node,
+      /* FunctionExpression|MethodDeclaration */ function) {
+    visitMemberMetadata(node.metadata);
+
+    // Nest the signature in case we have to split between the return type and
+    // name.
+    builder.nestExpression();
+    builder.startSpan();
+    modifier(node.externalKeyword);
+    if (node is MethodDeclaration) modifier(node.modifierKeyword);
+    visit(node.returnType, after: soloSplit);
+    modifier(node.propertyKeyword);
+    if (node is MethodDeclaration) modifier(node.operatorKeyword);
+    visit(node.name);
+    builder.endSpan();
+
+    // If the body is a block, we need to exit any nesting first. If it's an
+    // expression, we want to wrap the nesting around that so that the body
+    // gets nested farther.
+    if (function.body is! ExpressionFunctionBody) builder.unnest();
+
+    _visitBody(function.parameters, function.body);
+
+    if (function.body is ExpressionFunctionBody) builder.unnest();
+  }
+
   /// Visit the given function [parameters] followed by its [body], printing a
   /// space before it if it's not empty.
   ///
@@ -1611,16 +1756,15 @@
       builder.nestExpression();
 
       // This rule is ended by visitExpressionFunctionBody().
-      builder.startLazyRule(new SimpleRule(cost: Cost.arrow));
+      builder.startLazyRule(new Rule(Cost.arrow));
     }
 
     if (parameters != null) {
       builder.nestExpression();
-
       visit(parameters);
-      if (afterParameters != null) afterParameters();
-
       builder.unnest();
+
+      if (afterParameters != null) afterParameters();
     }
 
     visit(body);
@@ -1628,6 +1772,29 @@
     if (body is ExpressionFunctionBody) builder.unnest();
   }
 
+  /// Visits the body statement of a `for` or `for in` loop.
+  void _visitLoopBody(Statement body) {
+    if (body is EmptyStatement) {
+      // No space before the ";".
+      visit(body);
+    } else if (body is Block) {
+      space();
+      visit(body);
+    } else {
+      // Allow splitting in an expression-bodied for even though it's against
+      // the style guide. Since we can't fix the code itself to follow the
+      // style guide, we should at least format it as well as we can.
+      builder.nestExpression(indent: 2, now: true);
+      builder.startRule();
+
+      split();
+      visit(body);
+
+      builder.endRule();
+      builder.unnest();
+    }
+  }
+
   /// Visit a list of [nodes] if not null, optionally separated and/or preceded
   /// and followed by the given functions.
   void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) {
@@ -1674,10 +1841,6 @@
     if (elements.isEmpty && rightBracket.precedingComments == null) {
       token(leftBracket);
       token(rightBracket);
-
-      // Clear this out in case this empty collection is in an argument list.
-      // We don't want this rule to bleed over to some other collection.
-      _nextLiteralBodyRule = null;
       return;
     }
 
@@ -1694,7 +1857,7 @@
     // Always use a hard rule to split the elements. The parent chunk of
     // the collection will handle the unsplit case, so this only comes
     // into play when the collection is split.
-    var rule = new HardSplitRule();
+    var rule = new Rule.hard();
     builder.startRule(rule);
 
     // If a collection contains a line comment, we assume it's a big complex
@@ -1712,7 +1875,7 @@
             soloSplit();
           }
         } else {
-          builder.blockSplit(space: true);
+          builder.split(nest: false, space: true);
         }
       }
 
@@ -1733,6 +1896,37 @@
     _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force);
   }
 
+  /// Gets the cost to split at an assignment (or `:` in the case of a named
+  /// default value) with the given [rightHandSide].
+  ///
+  /// "Block-like" expressions (collections and cascades) bind a bit tighter
+  /// because it looks better to have code like:
+  ///
+  ///     var list = [
+  ///       element,
+  ///       element,
+  ///       element
+  ///     ];
+  ///
+  ///     var builder = new SomeBuilderClass()
+  ///       ..method()
+  ///       ..method();
+  ///
+  /// over:
+  ///
+  ///     var list =
+  ///         [element, element, element];
+  ///
+  ///     var builder =
+  ///         new SomeBuilderClass()..method()..method();
+  int _assignmentCost(Expression rightHandSide) {
+    if (rightHandSide is ListLiteral) return Cost.assignBlock;
+    if (rightHandSide is MapLiteral) return Cost.assignBlock;
+    if (rightHandSide is CascadeExpression) return Cost.assignBlock;
+
+    return Cost.assign;
+  }
+
   /// Returns `true` if the collection withs [elements] delimited by
   /// [rightBracket] contains any line comments.
   ///
@@ -1765,16 +1959,21 @@
   void _startLiteralBody(Token leftBracket) {
     token(leftBracket);
 
-    // Split the literal. Use the explicitly given rule if we have one.
-    // Otherwise, create a new rule.
-    var rule = _nextLiteralBodyRule;
-    _nextLiteralBodyRule = null;
+    // See if this literal is associated with an argument list that wants to
+    // handle splitting and indenting it. If not, we'll use a default rule.
+    var rule;
+    var argumentChunk;
+    if (_collectionArgumentLists.containsKey(leftBracket)) {
+      var argumentList = _collectionArgumentLists[leftBracket];
+      rule = argumentList.collectionRule;
+      argumentChunk = argumentList.previousSplit;
+    }
 
     // Create a rule for whether or not to split the block contents.
     builder.startRule(rule);
 
     // Process the collection contents as a separate set of chunks.
-    builder = builder.startBlock();
+    builder = builder.startBlock(argumentChunk);
   }
 
   /// Ends the literal body started by a call to [_startLiteralBody()].
@@ -1834,10 +2033,13 @@
     builder.unnest();
   }
 
-  /// Makes [rule] the rule that will be used for the contents of a collection
-  /// or function literal body that are about to be visited.
-  void setNextLiteralBodyRule(Rule rule) {
-    _nextLiteralBodyRule = rule;
+  /// Marks the collection literal that starts with [leftBracket] as being
+  /// controlled by [argumentList].
+  ///
+  /// When the collection is visited, [argumentList] will determine the
+  /// indentation and splitting rule for the collection.
+  void beforeCollection(Token leftBracket, ArgumentSublist argumentList) {
+    _collectionArgumentLists[leftBracket] = argumentList;
   }
 
   /// Writes an bracket-delimited body and handles indenting and starting the
@@ -1854,14 +2056,14 @@
 
     // Split after the bracket.
     builder.startRule();
-    builder.blockSplit(space: space, isDouble: false);
+    builder.split(isDouble: false, nest: false, space: space);
 
     body();
 
     token(rightBracket, before: () {
       // Split before the closing bracket character.
       builder.unindent();
-      builder.blockSplit(space: space);
+      builder.split(nest: false, space: space);
     });
 
     builder.endRule();
@@ -1869,7 +2071,8 @@
 
   /// Returns `true` if [node] is immediately contained within an anonymous
   /// [FunctionExpression].
-  bool _isInLambda(AstNode node) => node.parent is FunctionExpression &&
+  bool _isInLambda(AstNode node) =>
+      node.parent is FunctionExpression &&
       node.parent.parent is! FunctionDeclaration;
 
   /// Writes the string literal [string] to the output.
@@ -1945,7 +2148,7 @@
 
   /// Writes a single space split with its own rule.
   void soloSplit([int cost]) {
-    builder.startRule(new SimpleRule(cost: cost));
+    builder.startRule(new Rule(cost));
     split();
     builder.endRule();
   }
diff --git a/packages/dart_style/lib/src/whitespace.dart b/packages/dart_style/lib/src/whitespace.dart
index 481f498..b217fa1 100644
--- a/packages/dart_style/lib/src/whitespace.dart
+++ b/packages/dart_style/lib/src/whitespace.dart
@@ -17,18 +17,6 @@
 
   /// The ":" on a wrapped constructor initialization list.
   static const constructorInitializer = 4;
-
-  /// The indentation for subsequent variables when a for loop defines multiple
-  /// variables that wrap, like:
-  ///
-  ///     for (var a = initializer,
-  ///             b = another,
-  ///             c = third;
-  ///         a + b + c < 100;
-  ///         a++) {
-  ///       ...
-  ///     }
-  static const loopVariable = 8;
 }
 
 /// The kind of pending whitespace that has been "written", but not actually
diff --git a/packages/dart_style/pubspec.yaml b/packages/dart_style/pubspec.yaml
index 46f2018..c165eb8 100644
--- a/packages/dart_style/pubspec.yaml
+++ b/packages/dart_style/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dart_style
-version: 0.2.0
+version: 0.2.1
 author: Dart Team <misc@dartlang.org>
 description: Opinionated, automatic Dart source code formatter.
 homepage: https://github.com/dart-lang/dart_style
@@ -8,13 +8,16 @@
 dependencies:
   analyzer: '>=0.25.0 <0.27.0'
   args: '>=0.12.1 <0.14.0'
-  collection: '^1.0.0'
   path: '>=1.0.0 <2.0.0'
   source_span: '>=1.1.1 <2.0.0'
 dev_dependencies:
+  async: '>=1.0.0 <=2.0.0'
   browser: '>=0.10.0 <0.11.0'
+  grinder: '^0.7.2'
+  pub_semver: '^1.2.3'
   scheduled_test: '>=0.12.0 <0.13.0'
   test: '>=0.12.0 <0.13.0'
+  yaml: '^2.0.0'
 executables:
   dartfmt: format
   dartformat: format # Allow the old name for compatibility.
diff --git a/packages/dart_style/test/command_line_test.dart b/packages/dart_style/test/command_line_test.dart
index de64449..425143d 100644
--- a/packages/dart_style/test/command_line_test.dart
+++ b/packages/dart_style/test/command_line_test.dart
@@ -16,62 +16,85 @@
 void main() {
   setUpTestSuite();
 
-  test("Exits with 0 on success.", () {
+  test("exits with 0 on success", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatterOnDir();
     process.shouldExit(0);
   });
 
-  test("Exits with 64 on a command line argument error.", () {
+  test("exits with 64 on a command line argument error", () {
     var process = runFormatterOnDir(["-wat"]);
     process.shouldExit(64);
   });
 
-  test("Exits with 65 on a parse error.", () {
+  test("exits with 65 on a parse error", () {
     d.dir("code", [d.file("a.dart", "herp derp i are a dart")]).create();
 
     var process = runFormatterOnDir();
     process.shouldExit(65);
   });
 
-  test("Errors if --dry-run and --overwrite are both passed.", () {
+  test("errors if --dry-run and --overwrite are both passed", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatterOnDir(["--dry-run", "--overwrite"]);
     process.shouldExit(64);
   });
 
-  test("Errors if --dry-run and --machine are both passed.", () {
+  test("errors if --dry-run and --machine are both passed", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatterOnDir(["--dry-run", "--machine"]);
     process.shouldExit(64);
   });
 
-  test("Errors if --machine and --overwrite are both passed.", () {
+  test("errors if --machine and --overwrite are both passed", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatterOnDir(["--machine", "--overwrite"]);
     process.shouldExit(64);
   });
 
-  test("Errors if --dry-run and --machine are both passed.", () {
+  test("errors if --dry-run and --machine are both passed", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatter(["--dry-run", "--machine"]);
     process.shouldExit(64);
   });
 
-  test("Errors if --machine and --overwrite are both passed.", () {
+  test("errors if --machine and --overwrite are both passed", () {
     d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
     var process = runFormatter(["--machine", "--overwrite"]);
     process.shouldExit(64);
   });
 
+  test("--version prints the version number", () {
+    var process = runFormatter(["--version"]);
+
+    // Match something roughly semver-like.
+    process.stdout.expect(matches(r"\d+\.\d+\.\d+.*"));
+    process.shouldExit(0);
+  });
+
+  test("only prints a hidden directory once", () {
+    d.dir('code', [
+      d.dir('.skip', [
+        d.file('a.dart', unformattedSource),
+        d.file('b.dart', unformattedSource)
+      ])
+    ]).create();
+
+    var process = runFormatterOnDir();
+
+    process.stdout.expect(startsWith("Formatting directory"));
+    process.stdout.expect("Skipping hidden path ${p.join("code", ".skip")}");
+    process.shouldExit();
+  });
+
   group("--dry-run", () {
-    test("prints names of files that would change.", () {
+    test("prints names of files that would change", () {
       d.dir("code", [
         d.file("a_bad.dart", unformattedSource),
         d.file("b_good.dart", formattedSource),
@@ -90,7 +113,7 @@
       process.shouldExit();
     });
 
-    test("does not modify files.", () {
+    test("does not modify files", () {
       d.dir("code", [d.file("a.dart", unformattedSource)]).create();
 
       var process = runFormatterOnDir(["--dry-run"]);
@@ -130,12 +153,12 @@
   });
 
   group("--preserve", () {
-    test("errors if given paths.", () {
+    test("errors if given paths", () {
       var process = runFormatter(["--preserve", "path", "another"]);
       process.shouldExit(64);
     });
 
-    test("errors on wrong number of components.", () {
+    test("errors on wrong number of components", () {
       var process = runFormatter(["--preserve", "1"]);
       process.shouldExit(64);
 
@@ -143,12 +166,12 @@
       process.shouldExit(64);
     });
 
-    test("errors on non-integer component.", () {
+    test("errors on non-integer component", () {
       var process = runFormatter(["--preserve", "1:2.3"]);
       process.shouldExit(64);
     });
 
-    test("updates selection.", () {
+    test("updates selection", () {
       var process = runFormatter(["--preserve", "6:10", "-m"]);
       process.writeLine(unformattedSource);
       process.closeStdin();
@@ -164,20 +187,43 @@
     });
   });
 
+  group("--indent", () {
+    test("sets the leading indentation of the output", () {
+      var process = runFormatter(["--indent", "3"]);
+      process.writeLine("main() {'''");
+      process.writeLine("a flush left multi-line string''';}");
+      process.closeStdin();
+
+      process.stdout.expect("   main() {");
+      process.stdout.expect("     '''");
+      process.stdout.expect("a flush left multi-line string''';");
+      process.stdout.expect("   }");
+      process.shouldExit(0);
+    });
+
+    test("errors if the indent is not a non-negative number", () {
+      var process = runFormatter(["--indent", "notanum"]);
+      process.shouldExit(64);
+
+      process = runFormatter(["--preserve", "-4"]);
+      process.shouldExit(64);
+    });
+  });
+
   group("with no paths", () {
-    test("errors on --overwrite.", () {
+    test("errors on --overwrite", () {
       var process = runFormatter(["--overwrite"]);
       process.shouldExit(64);
     });
 
-    test("exits with 65 on parse error.", () {
+    test("exits with 65 on parse error", () {
       var process = runFormatter();
       process.writeLine("herp derp i are a dart");
       process.closeStdin();
       process.shouldExit(65);
     });
 
-    test("reads from stdin.", () {
+    test("reads from stdin", () {
       var process = runFormatter();
       process.writeLine(unformattedSource);
       process.closeStdin();
diff --git a/packages/dart_style/test/formatter_test.dart b/packages/dart_style/test/formatter_test.dart
index d227133..b50271f 100644
--- a/packages/dart_style/test/formatter_test.dart
+++ b/packages/dart_style/test/formatter_test.dart
@@ -149,7 +149,8 @@
     }
 
     group("$name ${p.basename(entry.path)}", () {
-      var lines = (entry as File).readAsLinesSync();
+      // Explicitly create a File, in case the entry is a Link.
+      var lines = new File(entry.path).readAsLinesSync();
 
       // The first line may have a "|" to indicate the page width.
       var pageWidth;
@@ -207,7 +208,13 @@
           var actualText = actual.text;
           if (!isCompilationUnit) actualText += "\n";
 
-          expect(actualText, equals(expected.text));
+          // Fail with an explicit message because it's easier to read than
+          // the matcher output.
+          if (actualText != expected.text) {
+            fail("Formatting did not match expectation. Expected:\n"
+                "${expected.text}\nActual:\n$actualText");
+          }
+
           expect(actual.selectionStart, equals(expected.selectionStart));
           expect(actual.selectionLength, equals(expected.selectionLength));
         });
diff --git a/packages/dart_style/test/io_test.dart b/packages/dart_style/test/io_test.dart
index 3962de6..64acf4c 100644
--- a/packages/dart_style/test/io_test.dart
+++ b/packages/dart_style/test/io_test.dart
@@ -156,8 +156,8 @@
         processDirectory(overwriteOptions, dir);
       }, 'Run formatter.');
 
-      d.dir('code', [d.file('linked_file.dart', unformattedSource),])
-          .validate();
+      d.dir(
+          'code', [d.file('linked_file.dart', unformattedSource),]).validate();
     });
 
     test("follows file symlinks when 'followLinks' is true", () {
diff --git a/packages/dart_style/test/regression/0000/0005.stmt b/packages/dart_style/test/regression/0000/0005.stmt
index e1d9b89..cba7a18 100644
--- a/packages/dart_style/test/regression/0000/0005.stmt
+++ b/packages/dart_style/test/regression/0000/0005.stmt
@@ -4,7 +4,8 @@
     path.isWithin(rootDirectory, directory)).toList();
 <<<
 var overlapping = _directories.keys
-    .where((directory) => path.isWithin(directory, rootDirectory) ||
+    .where((directory) =>
+        path.isWithin(directory, rootDirectory) ||
         path.isWithin(rootDirectory, directory))
     .toList();
 >>>
diff --git a/packages/dart_style/test/regression/0000/0006.stmt b/packages/dart_style/test/regression/0000/0006.stmt
index ed8ad97..e7d45c2 100644
--- a/packages/dart_style/test/regression/0000/0006.stmt
+++ b/packages/dart_style/test/regression/0000/0006.stmt
@@ -10,5 +10,6 @@
     messageMentions(id.toString()) ||
     messageMentions(path.fromUri(entry.assetId.path));
 <<<
-messageMentionsAsset(id) => messageMentions(id.toString()) ||
+messageMentionsAsset(id) =>
+    messageMentions(id.toString()) ||
     messageMentions(path.fromUri(entry.assetId.path));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0000/0026.stmt b/packages/dart_style/test/regression/0000/0026.stmt
index b5a1c7e..4fa6c76 100644
--- a/packages/dart_style/test/regression/0000/0026.stmt
+++ b/packages/dart_style/test/regression/0000/0026.stmt
@@ -6,4 +6,4 @@
 <<<
 experimentalBootstrap = document.querySelectorAll('link').any((link) =>
     link.attributes['rel'] == 'import' &&
-        link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML);
\ No newline at end of file
+    link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0000/0045.stmt b/packages/dart_style/test/regression/0000/0045.stmt
index de743a8..661344f 100644
--- a/packages/dart_style/test/regression/0000/0045.stmt
+++ b/packages/dart_style/test/regression/0000/0045.stmt
@@ -5,7 +5,6 @@
 }
 <<<
 foo() {
-  if (xxxxxxxxxxxxxxxx || xxxxxxxxxxxxxxxxxxxxx) return xxxxxxxxxxxxxx
-      ? xxxxxxxxxxxxxxxxxxxx
-      : xxxxxxxxxxxxxxxxxxxxxxxxxx;
+  if (xxxxxxxxxxxxxxxx || xxxxxxxxxxxxxxxxxxxxx)
+    return xxxxxxxxxxxxxx ? xxxxxxxxxxxxxxxxxxxx : xxxxxxxxxxxxxxxxxxxxxxxxxx;
 }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0000/0046.stmt b/packages/dart_style/test/regression/0000/0046.stmt
index 3897265..74cea63 100644
--- a/packages/dart_style/test/regression/0000/0046.stmt
+++ b/packages/dart_style/test/regression/0000/0046.stmt
@@ -7,6 +7,6 @@
 <<<
 foo() {
   if (true)
-      // comment!
-      return 0;
+    // comment!
+    return 0;
 }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0000/0076.unit b/packages/dart_style/test/regression/0000/0076.unit
index 0c6dd96..632b8e1 100644
--- a/packages/dart_style/test/regression/0000/0076.unit
+++ b/packages/dart_style/test/regression/0000/0076.unit
@@ -4,7 +4,8 @@
 }
 <<<
 class TokenType {
-  bool get isUserDefinableOperator => identical(lexeme, "==") ||
+  bool get isUserDefinableOperator =>
+      identical(lexeme, "==") ||
       identical(lexeme, "~") ||
       identical(lexeme, "[]") ||
       identical(lexeme, "[]=") ||
diff --git a/packages/dart_style/test/regression/0100/0108.unit b/packages/dart_style/test/regression/0100/0108.unit
index 64522f2..59bb316 100644
--- a/packages/dart_style/test/regression/0100/0108.unit
+++ b/packages/dart_style/test/regression/0100/0108.unit
@@ -51,7 +51,8 @@
                                             javaBooleanAnd(
                                                 _isEqualNodes(
                                                     node.documentationComment,
-                                                    toNode.documentationComment),
+                                                    toNode
+                                                        .documentationComment),
                                                 _isEqualNodeLists(node.metadata,
                                                     toNode.metadata)),
                                             _isEqualTokens(node.abstractKeyword,
@@ -145,7 +146,8 @@
                                             javaBooleanAnd(
                                                 _isEqualNodes(
                                                     node.documentationComment,
-                                                    toNode.documentationComment),
+                                                    toNode
+                                                        .documentationComment),
                                                 _isEqualNodeLists(
                                                     node.metadata,
                                                     _isEqualNodeLists(
@@ -155,11 +157,14 @@
                                                             _isEqualNodeLists(
                                                                 node.metadata,
                                                                 _isEqualNodeLists(
-                                                                    node.metadata,
+                                                                    node
+                                                                        .metadata,
                                                                     _isEqualNodeLists(
-                                                                        node.metadata,
+                                                                        node
+                                                                            .metadata,
                                                                         _isEqualNodeLists(
-                                                                            node.metadata,
+                                                                            node
+                                                                                .metadata,
                                                                             _isEqualNodeLists(node.metadata,
                                                                                 _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, _isEqualNodeLists(node.metadata, toNode.metadata))))))))))))))))))))))),
                                             _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword)),
@@ -209,9 +214,12 @@
 <<<
 async.Future<List<dom.StyleElement>> call(String tag, List<String> cssUrls, {Type type}) =>
     (DDC$RT.cast(
-        async.Future.wait(
-            (DDC$RT.cast(cssUrls.map((url) => _styleElement(tag, (DDC$RT.cast(url, String, key: "Cast failed: package:angular/core_dom/component_css_loader.dart:17:65")), type)),
-                DDC$RT.type((Iterable<Future<dynamic>> _) {
-    }), key: "Cast failed: package:angular/core_dom/component_css_loader.dart:17:25"))),
+        async.Future.wait((DDC$RT.cast(
+            cssUrls.map((url) => _styleElement(
+                tag,
+                (DDC$RT.cast(url, String, key: "Cast failed: package:angular/core_dom/component_css_loader.dart:17:65")),
+                type)),
+            DDC$RT.type((Iterable<Future<dynamic>> _) {}),
+            key: "Cast failed: package:angular/core_dom/component_css_loader.dart:17:25"))),
         DDC$RT.type((Future<List<StyleElement>> _) {}),
         key: "Cast failed: package:angular/core_dom/component_css_loader.dart:17:7"));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0100/0130.unit b/packages/dart_style/test/regression/0100/0130.unit
index 8974b73..d63287b 100644
--- a/packages/dart_style/test/regression/0100/0130.unit
+++ b/packages/dart_style/test/regression/0100/0130.unit
@@ -4,7 +4,8 @@
           _borderWidth +
       clientY;
 <<<
-  int get screenY => window.screenTop +
+  int get screenY =>
+      window.screenTop +
       window.outerHeight -
       window.innerHeight -
       _borderWidth +
diff --git a/packages/dart_style/test/regression/0100/0162.stmt b/packages/dart_style/test/regression/0100/0162.stmt
index daa92ac..5936f6f 100644
--- a/packages/dart_style/test/regression/0100/0162.stmt
+++ b/packages/dart_style/test/regression/0100/0162.stmt
@@ -28,22 +28,19 @@
 }
 <<<
 void main() {
-  useGeneratedCode(new StaticConfiguration(
-      checkedMode: false,
-      parents: {
-        smoke_0.A: smoke_1.PolymerElement,
-        smoke_0.B: smoke_0.A,
-        smoke_0.C: smoke_0.B,
-        smoke_0.D: smoke_0.B,
-        smoke_0.E: smoke_0.C,
-      },
-      declarations: {
-        smoke_0.A: {},
-        smoke_0.B: {},
-        smoke_0.C: {},
-        smoke_0.D: {},
-        smoke_0.E: {},
-      }));
+  useGeneratedCode(new StaticConfiguration(checkedMode: false, parents: {
+    smoke_0.A: smoke_1.PolymerElement,
+    smoke_0.B: smoke_0.A,
+    smoke_0.C: smoke_0.B,
+    smoke_0.D: smoke_0.B,
+    smoke_0.E: smoke_0.C,
+  }, declarations: {
+    smoke_0.A: {},
+    smoke_0.B: {},
+    smoke_0.C: {},
+    smoke_0.D: {},
+    smoke_0.E: {},
+  }));
   new LogInjector().injectLogsFromUrl('sort_registration_test.html._buildLogs');
   configureForDeployment([
     () => Polymer.register('x-a', i0.A),
diff --git a/packages/dart_style/test/regression/0200/0221.unit b/packages/dart_style/test/regression/0200/0221.unit
index a76f236..ab5fb23 100644
--- a/packages/dart_style/test/regression/0200/0221.unit
+++ b/packages/dart_style/test/regression/0200/0221.unit
@@ -12,10 +12,12 @@
 class Foo {
   static Column column(Handler onSelection) =>
       (Column.defaultBuilder(videoMsg())
-        ..id = 'VIDEO'
-        ..segment = ((row) =>
-            row.segmentedStats.map((s) => s.get(Stats.SEGMENTATION)).toList())
-        ..cell = new Cell(onSelection)).build();
+            ..id = 'VIDEO'
+            ..segment = ((row) => row.segmentedStats
+                .map((s) => s.get(Stats.SEGMENTATION))
+                .toList())
+            ..cell = new Cell(onSelection))
+          .build();
 }
 >>>
 void _updateChart() {
@@ -33,11 +35,13 @@
 void _updateChart() {
   if (_model.settings != null) {
     _chart.update((ChartSettings.builder()
-      ..ids.addAll(_model.ids)
-      ..statusFilter = StatusFilter.ALL
-      ..dateRange = chartDates.toChartDateRange(_model.settings.dateRange.value)
-      ..segmentationDimension = _model.segmentation
-      ..context = ChartContext.empty).build());
+          ..ids.addAll(_model.ids)
+          ..statusFilter = StatusFilter.ALL
+          ..dateRange =
+              chartDates.toChartDateRange(_model.settings.dateRange.value)
+          ..segmentationDimension = _model.segmentation
+          ..context = ChartContext.empty)
+        .build());
   }
 }
 >>> (indent 2)
@@ -56,12 +60,13 @@
   void _updateChart() {
     if (_model.settings != null) {
       _chart.update((ChartSettings.builder()
-        ..ids.addAll(_model.ids)
-        ..statusFilter = StatusFilter.ALL
-        ..dateRange =
-            chartDates.toChartDateRange(_model.settings.dateRange.value)
-        ..segmentationDimension = _model.segmentation
-        ..context = ChartContext.empty).build());
+            ..ids.addAll(_model.ids)
+            ..statusFilter = StatusFilter.ALL
+            ..dateRange =
+                chartDates.toChartDateRange(_model.settings.dateRange.value)
+            ..segmentationDimension = _model.segmentation
+            ..context = ChartContext.empty)
+          .build());
     }
   }
 >>>
@@ -90,8 +95,9 @@
 <<<
 main() {
   (new OrderBy()
-    ..field = s.column
-    ..sortOrder = s.isAscending
-        ? OrderBySortOrder.ASCENDING
-        : OrderBySortOrder.DESCENDING).toList();
+        ..field = s.column
+        ..sortOrder = s.isAscending
+            ? OrderBySortOrder.ASCENDING
+            : OrderBySortOrder.DESCENDING)
+      .toList();
 }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0200/0224.stmt b/packages/dart_style/test/regression/0200/0224.stmt
index 11c8726..c2bfca8 100644
--- a/packages/dart_style/test/regression/0200/0224.stmt
+++ b/packages/dart_style/test/regression/0200/0224.stmt
@@ -31,14 +31,15 @@
             ]))
         .catchError(cannotGetConveyorBeltRunning)
         .then((_) => tellEveryoneDonutsAreJustAboutDone())
-        .then((_) => Future.wait([
+        .then((_) => Future
+            .wait([
               croissantFactory.start(),
               _giantBakingOvens.start(),
               butterbutterer.start()
             ])
-                .catchError(_handleBakingFailures)
-                .timeout(scriptLoadingTimeout, onTimeout: _handleBakingFailures)
-                .catchError(cannotGetConveyorBeltRunning))
+            .catchError(_handleBakingFailures)
+            .timeout(scriptLoadingTimeout, onTimeout: _handleBakingFailures)
+            .catchError(cannotGetConveyorBeltRunning))
         .catchError(cannotGetConveyorBeltRunning)
         .then((_) {
       _logger.info("Let's eat!");
diff --git a/packages/dart_style/test/regression/0200/0243.stmt b/packages/dart_style/test/regression/0200/0243.stmt
index d4c6fa5..b75dc65 100644
--- a/packages/dart_style/test/regression/0200/0243.stmt
+++ b/packages/dart_style/test/regression/0200/0243.stmt
@@ -7,12 +7,10 @@
               style: _content_style,
               children: appChildren)]);
 <<<
-    return new Container(
-        key: 'ChatApp',
-        children: [
-          new Container(
-              key: 'Content', style: _content_style, children: appChildren)
-        ]);
+    return new Container(key: 'ChatApp', children: [
+      new Container(
+          key: 'Content', style: _content_style, children: appChildren)
+    ]);
 >>> (indent 10)
           return new Container(
               key: 'ChatApp',
@@ -22,11 +20,7 @@
                     style: _content_style,
                     children: appChildren)]);
 <<<
-          return new Container(
-              key: 'ChatApp',
-              children: [
-                new Container(
-                    key: 'Content',
-                    style: _content_style,
-                    children: appChildren)
-              ]);
\ No newline at end of file
+          return new Container(key: 'ChatApp', children: [
+            new Container(
+                key: 'Content', style: _content_style, children: appChildren)
+          ]);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0200/0247.unit b/packages/dart_style/test/regression/0200/0247.unit
index 0a845a7..218c2bd 100644
--- a/packages/dart_style/test/regression/0200/0247.unit
+++ b/packages/dart_style/test/regression/0200/0247.unit
@@ -10,8 +10,8 @@
 <<<
   init(
       {@Option(help: 'The git Uri containing the jefe.yaml.', abbr: 'g')
-      String gitUri,
+          String gitUri,
       @Option(help: 'The directory to install into', abbr: 'd')
-      String installDirectory: '.',
+          String installDirectory: '.',
       @Flag(help: 'Skips the checkout of the develop branch', abbr: 's')
-      bool skipCheckout: false}) async {}
\ No newline at end of file
+          bool skipCheckout: false}) async {}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0200/0255.stmt b/packages/dart_style/test/regression/0200/0255.stmt
new file mode 100644
index 0000000..283e9fc
--- /dev/null
+++ b/packages/dart_style/test/regression/0200/0255.stmt
@@ -0,0 +1,10 @@
+>>> (indent 10)
+          return new Rewriter(code, codegen,
+              mirrorMode: mirrorMode, writeStaticInit: writeStaticInit).rewrite(
+              parseCompilationUnit(code,
+                  name: reflectionEntryPointPath, parseFunctionBodies: false));
+<<<
+          return new Rewriter(code, codegen,
+                  mirrorMode: mirrorMode, writeStaticInit: writeStaticInit)
+              .rewrite(parseCompilationUnit(code,
+                  name: reflectionEntryPointPath, parseFunctionBodies: false));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0200/0258.unit b/packages/dart_style/test/regression/0200/0258.unit
index 9e9466c..a2c1f25 100644
--- a/packages/dart_style/test/regression/0200/0258.unit
+++ b/packages/dart_style/test/regression/0200/0258.unit
@@ -18,7 +18,7 @@
             GGGGGGGGConfigFactory, HHHHHHHHHHHHHConfigFactory),
         _aaaaaaaaaaaConfig = _getaaaaaaaaaaaConfig(
             GGGGGGGGConfigFactory, HHHHHHHHHHHHHConfigFactory),
-        _defaultFFFFFFFConfig = FFFFFFFConfigurationStore
-            ._getDefaultFFFFFFFConfig(
+        _defaultFFFFFFFConfig =
+            FFFFFFFConfigurationStore._getDefaultFFFFFFFConfig(
                 GGGGGGGGConfigFactory, HHHHHHHHHHHHHConfigFactory);
 }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0357.stmt b/packages/dart_style/test/regression/0300/0357.stmt
new file mode 100644
index 0000000..bb27d07
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0357.stmt
@@ -0,0 +1,6 @@
+>>> (indent 2)
+  bool theMethodNameGoesHere(ParameterTyp result) => reallyLongIdentifier
+      .any((MyClass myParam) => myParam.id == result.myParam.id);
+<<<
+  bool theMethodNameGoesHere(ParameterTyp result) => reallyLongIdentifier
+      .any((MyClass myParam) => myParam.id == result.myParam.id);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0367.stmt b/packages/dart_style/test/regression/0300/0367.stmt
new file mode 100644
index 0000000..6108b7e
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0367.stmt
@@ -0,0 +1,31 @@
+>>> (indent 6)
+      identifier__ = identifier_____.identifier___
+          .transform(new StreamTransformer<TypeArg____, Type_>.fromHandlers(
+              handleData: (TypeName___ arg__, EventSink<Type_> arg_) {
+        ;
+      }))
+          .asBroadcastStream();
+<<<
+      identifier__ = identifier_____.identifier___.transform(
+          new StreamTransformer<TypeArg____, Type_>.fromHandlers(
+              handleData: (TypeName___ arg__, EventSink<Type_> arg_) {
+        ;
+      })).asBroadcastStream();
+>>> (indent 4)
+    _trigger
+        .then(ut.expectAsync((result) {
+      if (_deferExpectations == null || _deferExpectations == false) {
+        body(result);
+      } else {
+        defer(ut.expectAsync(() => body(result)));
+      }
+    }))
+        .catchError(ut.fail);
+<<<
+    _trigger.then(ut.expectAsync((result) {
+      if (_deferExpectations == null || _deferExpectations == false) {
+        body(result);
+      } else {
+        defer(ut.expectAsync(() => body(result)));
+      }
+    })).catchError(ut.fail);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0370.stmt b/packages/dart_style/test/regression/0300/0370.stmt
index 086bbf8..4f936d6 100644
--- a/packages/dart_style/test/regression/0300/0370.stmt
+++ b/packages/dart_style/test/regression/0300/0370.stmt
@@ -36,35 +36,40 @@
   return notFound(request, asset: id);
 });
 <<<
-return environment.barback.getAssetById(id).then((result) {
-  return result;
-}).then((asset) => _serveAsset(request, asset)).catchError((error, trace) {
-  if (error is! AssetNotFoundException) throw error;
-  return environment.barback
-      .getAssetById(id.addExtension("/index.html"))
-      .then((asset) {
-    if (request.url.path.endsWith('/')) return _serveAsset(request, asset);
+return environment.barback
+    .getAssetById(id)
+    .then((result) {
+      return result;
+    })
+    .then((asset) => _serveAsset(request, asset))
+    .catchError((error, trace) {
+      if (error is! AssetNotFoundException) throw error;
+      return environment.barback
+          .getAssetById(id.addExtension("/index.html"))
+          .then((asset) {
+        if (request.url.path.endsWith('/')) return _serveAsset(request, asset);
 
-    // We only want to serve index.html if the URL explicitly ends in a
-    // slash. For other URLs, we redirect to one with the slash added to
-    // implicitly support that too. This follows Apache's behavior.
-    logRequest(request, "302 Redirect to ${request.url}/");
-    return new shelf.Response.found('${request.url}/');
-  }).catchError((newError, newTrace) {
-    // If we find neither the original file or the index, we should report
-    // the error about the original to the user.
-    throw newError is AssetNotFoundException ? error : newError;
-  });
-}).catchError((error, trace) {
-  if (error is! AssetNotFoundException) {
-    trace = new Chain.forTrace(trace);
-    logRequest(request, "$error\n$trace");
+        // We only want to serve index.html if the URL explicitly ends in a
+        // slash. For other URLs, we redirect to one with the slash added to
+        // implicitly support that too. This follows Apache's behavior.
+        logRequest(request, "302 Redirect to ${request.url}/");
+        return new shelf.Response.found('${request.url}/');
+      }).catchError((newError, newTrace) {
+        // If we find neither the original file or the index, we should report
+        // the error about the original to the user.
+        throw newError is AssetNotFoundException ? error : newError;
+      });
+    })
+    .catchError((error, trace) {
+      if (error is! AssetNotFoundException) {
+        trace = new Chain.forTrace(trace);
+        logRequest(request, "$error\n$trace");
 
-    addError(error, trace);
-    close();
-    return new shelf.Response.internalServerError();
-  }
+        addError(error, trace);
+        close();
+        return new shelf.Response.internalServerError();
+      }
 
-  addResult(new BarbackServerResult._failure(request.url, id, error));
-  return notFound(request, asset: id);
-});
\ No newline at end of file
+      addResult(new BarbackServerResult._failure(request.url, id, error));
+      return notFound(request, asset: id);
+    });
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0373.unit b/packages/dart_style/test/regression/0300/0373.unit
new file mode 100644
index 0000000..25e4021
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0373.unit
@@ -0,0 +1,6 @@
+>>> (indent 4)
+    TreeNode lookupEntity(Iterable<TreeNode> iterable, int entity) => iterable
+        .firstWhere((node) => (node.entity == entity), orElse: () => null);
+<<<
+    TreeNode lookupEntity(Iterable<TreeNode> iterable, int entity) => iterable
+        .firstWhere((node) => (node.entity == entity), orElse: () => null);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0378.stmt b/packages/dart_style/test/regression/0300/0378.stmt
new file mode 100644
index 0000000..a7da1f0
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0378.stmt
@@ -0,0 +1,9 @@
+>>> (indent 4)
+    return new js.Fun(parameters, body, asyncModifier: asyncModifier)
+        .withSourceInformation(sourceInformationFactory.forContext(element)
+            .buildDeclaration(element));
+<<<
+    return new js.Fun(parameters, body, asyncModifier: asyncModifier)
+        .withSourceInformation(sourceInformationFactory
+            .forContext(element)
+            .buildDeclaration(element));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0384.stmt b/packages/dart_style/test/regression/0300/0384.stmt
index fa0c6fa..0fbaa33 100644
--- a/packages/dart_style/test/regression/0300/0384.stmt
+++ b/packages/dart_style/test/regression/0300/0384.stmt
@@ -3,4 +3,5 @@
         ErrorCollectingPublisher] as ErrorCollectingPublisher).verify();
 <<<
     (scubaMatchers.publishers[ErrorCollectingPublisher]
-        as ErrorCollectingPublisher).verify();
\ No newline at end of file
+            as ErrorCollectingPublisher)
+        .verify();
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0387.unit b/packages/dart_style/test/regression/0300/0387.unit
new file mode 100644
index 0000000..88fcfbc
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0387.unit
@@ -0,0 +1,19 @@
+>>>
+greet(@Rest(valueHelp: 'who', help: 'Name(s) to greet.') List<String> who,
+    {@Group.start(title: 'Output')
+    @Option(help: 'How many !\'s to append.')
+    int enthusiasm: 0,
+    @Flag(abbr: 'l', help: 'Put names on separate lines.') bool lineMode: false,
+    @Option(name: 'greeting', help: 'Alternate word to greet with e.g. "Hi".')
+    String salutation: 'Hello'}) {}
+<<<
+greet(
+    @Rest(valueHelp: 'who', help: 'Name(s) to greet.')
+        List<String> who,
+    {@Group.start(title: 'Output')
+    @Option(help: 'How many !\'s to append.')
+        int enthusiasm: 0,
+    @Flag(abbr: 'l', help: 'Put names on separate lines.')
+        bool lineMode: false,
+    @Option(name: 'greeting', help: 'Alternate word to greet with e.g. "Hi".')
+        String salutation: 'Hello'}) {}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0394.stmt b/packages/dart_style/test/regression/0300/0394.stmt
new file mode 100644
index 0000000..139851a
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0394.stmt
@@ -0,0 +1,26 @@
+>>>
+return $.Div(inner: [
+
+    $.Div(id: "container", inner: [
+        $.Canvas(width: maxD, height: maxD, clazz: "center", ref: canvas),
+        $.Form(clazz: "center", inner: [
+            $.Input(type: "range", max: 1000, value: seeds, onChange: onSliderChange)
+        ]),
+        $.Img(src: "math.png", width: "350px", height: "42px", clazz: "center")
+    ]),
+
+    $.Footer(inner: [
+        $.P(id: "notes", inner: "${seeds} seeds")
+    ]),
+]);
+<<<
+return $.Div(inner: [
+  $.Div(id: "container", inner: [
+    $.Canvas(width: maxD, height: maxD, clazz: "center", ref: canvas),
+    $.Form(clazz: "center", inner: [
+      $.Input(type: "range", max: 1000, value: seeds, onChange: onSliderChange)
+    ]),
+    $.Img(src: "math.png", width: "350px", height: "42px", clazz: "center")
+  ]),
+  $.Footer(inner: [$.P(id: "notes", inner: "${seeds} seeds")]),
+]);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0398.stmt b/packages/dart_style/test/regression/0300/0398.stmt
new file mode 100644
index 0000000..7eed34a
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0398.stmt
@@ -0,0 +1,11 @@
+>>> (indent 4)
+    children.add(new DrawerHeader(children: [
+        new Flex([avatar, username],
+            justifyContent: FlexJustifyContent.center,
+            direction: FlexDirection.vertical)]));
+<<<
+    children.add(new DrawerHeader(children: [
+      new Flex([avatar, username],
+          justifyContent: FlexJustifyContent.center,
+          direction: FlexDirection.vertical)
+    ]));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0300/0399.unit b/packages/dart_style/test/regression/0300/0399.unit
new file mode 100644
index 0000000..148eaa0
--- /dev/null
+++ b/packages/dart_style/test/regression/0300/0399.unit
@@ -0,0 +1,8 @@
+>>> (indent 2)
+  Optional<Cookie> getCookie(String name) => new Optional.fromNullable(_driver
+      .cookies
+      .all.firstWhere((cookie) => cookie.name == name, orElse: () => null));
+<<<
+  Optional<Cookie> getCookie(String name) =>
+      new Optional.fromNullable(_driver.cookies.all
+          .firstWhere((cookie) => cookie.name == name, orElse: () => null));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0404.stmt b/packages/dart_style/test/regression/0400/0404.stmt
new file mode 100644
index 0000000..9049632
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0404.stmt
@@ -0,0 +1,14 @@
+>>> (indent 2)
+  group('((prevent timeout))', () {
+    setUp(() => ensureImageExists());
+
+    test('((dummy))', () {
+    }, timeout: const Timeout(const Duration(seconds: 300)));
+  });
+<<<
+  group('((prevent timeout))', () {
+    setUp(() => ensureImageExists());
+
+    test('((dummy))', () {},
+        timeout: const Timeout(const Duration(seconds: 300)));
+  });
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0407.unit b/packages/dart_style/test/regression/0400/0407.unit
new file mode 100644
index 0000000..ca50851
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0407.unit
@@ -0,0 +1,33 @@
+>>>
+void main() {
+  model..account = (new Account()
+    ..accountId = new Int64(111)
+    ..tags = (new Account_Tags()..accountHotlist.add(new Hotlist()..hotlistId = new Int64(10))));
+}
+<<<
+void main() {
+  model
+    ..account = (new Account()
+      ..accountId = new Int64(111)
+      ..tags = (new Account_Tags()
+        ..accountHotlist.add(new Hotlist()..hotlistId = new Int64(10))));
+}
+>>> (indent 4)
+main() {
+receiver
+      ..formattedTotal = _total == 0
+          ? ""
+          : _chartType == "PieChart"
+              ? _formatter.formatAsPercent(item.value / _total, fractionDigits: 1)
+              : _formatter.formatValue(item.value, item.valueType);
+}
+<<<
+    main() {
+      receiver
+        ..formattedTotal = _total == 0
+            ? ""
+            : _chartType == "PieChart"
+                ? _formatter.formatAsPercent(item.value / _total,
+                    fractionDigits: 1)
+                : _formatter.formatValue(item.value, item.valueType);
+    }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0410.stmt b/packages/dart_style/test/regression/0400/0410.stmt
new file mode 100644
index 0000000..2aa5952
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0410.stmt
@@ -0,0 +1,53 @@
+>>>
+test(
+    'some test that has a very long description so the params need two lines',
+    async(() {
+    expect(
+        request.enabledApExperiments.contains(
+            ApExperimentName.SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+            isFalse);
+    }));
+<<<
+test('some test that has a very long description so the params need two lines',
+    async(() {
+  expect(
+      request.enabledApExperiments.contains(
+          ApExperimentName.SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+      isFalse);
+}));
+>>> (indent 2)
+test(
+    'some test that has a very long description so the params need two lines',
+    async(() {
+  expect(
+      request.enabledApExperiments.contains(
+          ApExperimentName.SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+        isFalse);
+}));
+<<<
+  test(
+      'some test that has a very long description so the params need two lines',
+      async(() {
+    expect(
+        request.enabledApExperiments.contains(
+            ApExperimentName.SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+        isFalse);
+  }));
+>>> (indent 4)
+test(
+    'some test that has a very long description so the params need two lines',
+    async(() {
+    expect(
+        request.enabledApExperiments.contains(
+            ApExperimentName.SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+            isFalse);
+    }));
+<<<
+    test(
+        'some test that has a very long description so the params need two lines',
+        async(() {
+      expect(
+          request.enabledApExperiments.contains(ApExperimentName
+              .SOME_VERY_LONG_ENUMS_THAT_LEADS_TO_MANY_PROBLEMS),
+          isFalse);
+    }));
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0413.unit b/packages/dart_style/test/regression/0400/0413.unit
new file mode 100644
index 0000000..e627126
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0413.unit
@@ -0,0 +1,10 @@
+>>>
+List get bindings => [
+    bind(const StaticFilePath())
+        .toValue(_staticFilePath.isEmpty ? _libRoot : _staticFilePath)
+  ];
+<<<
+List get bindings => [
+      bind(const StaticFilePath())
+          .toValue(_staticFilePath.isEmpty ? _libRoot : _staticFilePath)
+    ];
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0420.unit b/packages/dart_style/test/regression/0400/0420.unit
new file mode 100644
index 0000000..b4d14cc
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0420.unit
@@ -0,0 +1,35 @@
+>>>
+createSomeObject(String s, Int64 id,
+    {Map<String, Int64> mapFromStringToInt64}) => null;
+
+main() {
+  void group() {
+    void initialize() {
+      final SOME_SUPER_LONG_CONST = 'Foo';
+      var objects = [
+        createSomeObject(SOME_SUPER_LONG_CONST, new Int64(1), mapFromStringToInt64:
+            {'ONE': new Int64(1), 'TWO': new Int64(2), 'THREE': new Int64(3)}),
+      ];
+    }
+  }
+}
+<<<
+createSomeObject(String s, Int64 id,
+        {Map<String, Int64> mapFromStringToInt64}) =>
+    null;
+
+main() {
+  void group() {
+    void initialize() {
+      final SOME_SUPER_LONG_CONST = 'Foo';
+      var objects = [
+        createSomeObject(SOME_SUPER_LONG_CONST, new Int64(1),
+            mapFromStringToInt64: {
+              'ONE': new Int64(1),
+              'TWO': new Int64(2),
+              'THREE': new Int64(3)
+            }),
+      ];
+    }
+  }
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0421.unit b/packages/dart_style/test/regression/0400/0421.unit
new file mode 100644
index 0000000..ebd840c
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0421.unit
@@ -0,0 +1,82 @@
+>>>
+@Component(
+    selector: 'my-selector',
+    properties: const ['property-1', 'property-2', 'property-3', 'property-4', 'property-5'])
+@View(
+    directives: const [OtherComponent1, OtherComponent2, OtherComponent3, OtherDirective4, OtherDirective5, OtherDirective6, OtherDirective7,],
+    styleUrls: const ['package:path.to.my.amazing.component.library/my_amazing_component.scss.css'],
+    templateUrl: 'package:path.to.my.amazing.component.library/my_amazing_component.html')
+class MyAmazingComponent {
+  var a = [[[1]]];
+}
+<<<
+@Component(selector: 'my-selector', properties: const [
+  'property-1',
+  'property-2',
+  'property-3',
+  'property-4',
+  'property-5'
+])
+@View(
+    directives: const [
+      OtherComponent1,
+      OtherComponent2,
+      OtherComponent3,
+      OtherDirective4,
+      OtherDirective5,
+      OtherDirective6,
+      OtherDirective7,
+    ],
+    styleUrls: const [
+      'package:path.to.my.amazing.component.library/my_amazing_component.scss.css'
+    ],
+    templateUrl:
+        'package:path.to.my.amazing.component.library/my_amazing_component.html')
+class MyAmazingComponent {
+  var a = [
+    [
+      [1]
+    ]
+  ];
+}
+>>>
+@Component(
+    selector: 'my-selector',
+    properties: const ['property-1', 'property-2', 'property-3', 'property-4', 'property-5'])
+@View(
+    directives: const [OtherComponent1, OtherComponent2, OtherComponent3, OtherDirective4, OtherDirective5, OtherDirective6, OtherDirective7,],
+    templateUrl: 'package:path.to.my.amazing.component.library/my_amazing_component.html',
+    styleUrls: const ['package:path.to.my.amazing.component.library/my_amazing_component.scss.css'])
+class MyAmazingComponent {
+  var a = [[[1]]];
+}
+<<<
+@Component(selector: 'my-selector', properties: const [
+  'property-1',
+  'property-2',
+  'property-3',
+  'property-4',
+  'property-5'
+])
+@View(
+    directives: const [
+      OtherComponent1,
+      OtherComponent2,
+      OtherComponent3,
+      OtherDirective4,
+      OtherDirective5,
+      OtherDirective6,
+      OtherDirective7,
+    ],
+    templateUrl:
+        'package:path.to.my.amazing.component.library/my_amazing_component.html',
+    styleUrls: const [
+      'package:path.to.my.amazing.component.library/my_amazing_component.scss.css'
+    ])
+class MyAmazingComponent {
+  var a = [
+    [
+      [1]
+    ]
+  ];
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0422.unit b/packages/dart_style/test/regression/0400/0422.unit
new file mode 100644
index 0000000..ba60807
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0422.unit
@@ -0,0 +1,21 @@
+>>>
+void allTests() {
+  describe('inliner', () {
+    it('should inline `templateUrl` values', () async {
+      expect(view.namedParameters
+          .firstWhere((p) => p.name == 'templateUrl')
+          .value).toContain('template.html');
+    });
+  });
+}
+<<<
+void allTests() {
+  describe('inliner', () {
+    it('should inline `templateUrl` values', () async {
+      expect(view.namedParameters
+              .firstWhere((p) => p.name == 'templateUrl')
+              .value)
+          .toContain('template.html');
+    });
+  });
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0424.stmt b/packages/dart_style/test/regression/0400/0424.stmt
new file mode 100644
index 0000000..fc09d05
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0424.stmt
@@ -0,0 +1,13 @@
+>>>
+obj.functionWithTwoParameters(firstParameterGenerator()
+  ..id = myId
+  ..teamId = myTeamId
+  ..startTime = new Time(getEndOfDate(clock.currentTime()).millisecondsSinceEpoch), secondParameterGenerator());
+<<<
+obj.functionWithTwoParameters(
+    firstParameterGenerator()
+      ..id = myId
+      ..teamId = myTeamId
+      ..startTime =
+          new Time(getEndOfDate(clock.currentTime()).millisecondsSinceEpoch),
+    secondParameterGenerator());
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0429.stmt b/packages/dart_style/test/regression/0400/0429.stmt
new file mode 100644
index 0000000..411e7cd
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0429.stmt
@@ -0,0 +1,12 @@
+>>> (indent 2)
+  final Map<String,
+          SummaryTabDataRequest_CampaignSkinSubtype> _campaignSkinSubtypes =
+      new Map.fromIterable(SummaryTabDataRequest_CampaignSkinSubtype.values,
+          key: (campaignSkinSubtype) => campaignSkinSubtype.name,
+          value: (campaignSkinSubtype) => campaignSkinSubtype);
+<<<
+  final Map<String, SummaryTabDataRequest_CampaignSkinSubtype>
+      _campaignSkinSubtypes = new Map.fromIterable(
+          SummaryTabDataRequest_CampaignSkinSubtype.values,
+          key: (campaignSkinSubtype) => campaignSkinSubtype.name,
+          value: (campaignSkinSubtype) => campaignSkinSubtype);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0434.unit b/packages/dart_style/test/regression/0400/0434.unit
new file mode 100644
index 0000000..4089412
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0434.unit
@@ -0,0 +1,20 @@
+>>> (indent 2)
+  @eventHandler
+  bool computeChangePasswordDisabled(
+          String email, String password, String newPassword) =>
+      email == null ||
+          email.isEmpty ||
+          password == null ||
+          password.isEmpty ||
+          newPassword == null ||
+          newPassword.isEmpty;
+<<<
+  @eventHandler
+  bool computeChangePasswordDisabled(
+          String email, String password, String newPassword) =>
+      email == null ||
+      email.isEmpty ||
+      password == null ||
+      password.isEmpty ||
+      newPassword == null ||
+      newPassword.isEmpty;
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0436.unit b/packages/dart_style/test/regression/0400/0436.unit
new file mode 100644
index 0000000..bd83a42
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0436.unit
@@ -0,0 +1,17 @@
+>>>
+class Foo {
+  void main() {
+    List<TypeParameterElement> typeParameterElements = interfaceTypeContext
+            .element !=
+        null ? interfaceTypeContext.element.typeParameters : null;
+  }
+}
+<<<
+class Foo {
+  void main() {
+    List<TypeParameterElement> typeParameterElements =
+        interfaceTypeContext.element != null
+            ? interfaceTypeContext.element.typeParameters
+            : null;
+  }
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0437.unit b/packages/dart_style/test/regression/0400/0437.unit
new file mode 100644
index 0000000..3016314
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0437.unit
@@ -0,0 +1,22 @@
+>>>
+class Foo {
+  static ExportElementImpl exportFor(LibraryElement exportedLibrary,
+      [List<NamespaceCombinator> combinators = NamespaceCombinator
+          .EMPTY_LIST]) {
+    ExportElementImpl spec = new ExportElementImpl(-1);
+    spec.exportedLibrary = exportedLibrary;
+    spec.combinators = combinators;
+    return spec;
+  }
+}
+<<<
+class Foo {
+  static ExportElementImpl exportFor(LibraryElement exportedLibrary,
+      [List<NamespaceCombinator> combinators =
+          NamespaceCombinator.EMPTY_LIST]) {
+    ExportElementImpl spec = new ExportElementImpl(-1);
+    spec.exportedLibrary = exportedLibrary;
+    spec.combinators = combinators;
+    return spec;
+  }
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0438.stmt b/packages/dart_style/test/regression/0400/0438.stmt
new file mode 100644
index 0000000..19e237d
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0438.stmt
@@ -0,0 +1,6 @@
+>>>
+final JsFunction _setDartInstance = context['Polymer']['PolymerInterop']
+    ['setDartInstance'];
+<<<
+final JsFunction _setDartInstance =
+    context['Polymer']['PolymerInterop']['setDartInstance'];
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0439.stmt b/packages/dart_style/test/regression/0400/0439.stmt
new file mode 100644
index 0000000..bf44cae
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0439.stmt
@@ -0,0 +1,16 @@
+>>> (indent 2)
+  final aaaaaaaaaaaaaaaaaaaa = new Bbbbbbbbbbbbbbbbbbbbbbbb<
+      Cccccccc>((Cccccccc cc) =>
+      'ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd');
+<<<
+  final aaaaaaaaaaaaaaaaaaaa = new Bbbbbbbbbbbbbbbbbbbbbbbb<Cccccccc>(
+      (Cccccccc cc) =>
+          'ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd');
+>>> (indent 2)
+  final aaaaaaaaaaaaaaaaaaaa = new Bbbbbbbbbbbbbbbbbbbbbbbb<
+      Cccccccc>((Cccccccc cc) =>
+      'ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd');
+<<<
+  final aaaaaaaaaaaaaaaaaaaa = new Bbbbbbbbbbbbbbbbbbbbbbbb<Cccccccc>(
+      (Cccccccc cc) =>
+          'ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd');
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0441.unit b/packages/dart_style/test/regression/0400/0441.unit
new file mode 100644
index 0000000..787fbad
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0441.unit
@@ -0,0 +1,14 @@
+>>>
+getSomeFoo(
+    {fooooooooooooooooooooo: const [
+  'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+]}) {
+  return 'rhubarb';
+}
+<<<
+getSomeFoo(
+    {fooooooooooooooooooooo: const [
+      'baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+    ]}) {
+  return 'rhubarb';
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0443.unit b/packages/dart_style/test/regression/0400/0443.unit
new file mode 100644
index 0000000..16e3333
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0443.unit
@@ -0,0 +1,6 @@
+>>>
+@sg.GeneratedPart('package:injection/generator.dart')
+part 'app.injection.dart';
+<<<
+@sg.GeneratedPart('package:injection/generator.dart')
+part 'app.injection.dart';
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0444.unit b/packages/dart_style/test/regression/0400/0444.unit
new file mode 100644
index 0000000..944f0f2
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0444.unit
@@ -0,0 +1,26 @@
+>>>
+class MyComponent {
+  Object firstArgument;
+  Object superDuperLongNamedArgument;
+  Object secondArgument;
+
+  MyComponent(
+      @Inject(const MyFirstArgument()) this.firstArgument,
+      @Inject(const MySuperDuperLongNamedArgument())
+      this.superDuperLongNamedArgument, // LOOK AT ME
+      @Inject(const MySecondArgument()) this.secondArgument);
+}
+<<<
+class MyComponent {
+  Object firstArgument;
+  Object superDuperLongNamedArgument;
+  Object secondArgument;
+
+  MyComponent(
+      @Inject(const MyFirstArgument())
+          this.firstArgument,
+      @Inject(const MySuperDuperLongNamedArgument())
+          this.superDuperLongNamedArgument, // LOOK AT ME
+      @Inject(const MySecondArgument())
+          this.secondArgument);
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0448.stmt b/packages/dart_style/test/regression/0400/0448.stmt
new file mode 100644
index 0000000..09e0262
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0448.stmt
@@ -0,0 +1,34 @@
+>>> (indent 6)
+      if (t == 0.0)
+        value = begin;
+      else if (t == 1.0)
+        value = end;
+      else
+        value = lerp(t);
+<<<
+      if (t == 0.0)
+        value = begin;
+      else if (t == 1.0)
+        value = end;
+      else
+        value = lerp(t);
+>>> (indent 4)
+    if (direction == AnimationDirection.forward ||
+        reverseCurve == null) return curve;
+<<<
+    if (direction == AnimationDirection.forward || reverseCurve == null)
+      return curve;
+>>> (indent 6)
+      if (outputSize.width / outputSize.height > sourceSize.width / sourceSize.height)
+        destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, outputSize.height);
+      else
+        destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
+<<<
+      if (outputSize.width / outputSize.height >
+          sourceSize.width / sourceSize.height)
+        destinationSize = new Size(
+            sourceSize.width * outputSize.height / sourceSize.height,
+            outputSize.height);
+      else
+        destinationSize = new Size(outputSize.width,
+            sourceSize.height * outputSize.width / sourceSize.width);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0449.stmt b/packages/dart_style/test/regression/0400/0449.stmt
new file mode 100644
index 0000000..b4146da
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0449.stmt
@@ -0,0 +1,6 @@
+>>> (indent 4)
+    for (int i = 0; i < variables.length; ++i)
+      performance.updateVariable(variables[i]);
+<<<
+    for (int i = 0; i < variables.length; ++i)
+      performance.updateVariable(variables[i]);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0454.unit b/packages/dart_style/test/regression/0400/0454.unit
new file mode 100644
index 0000000..6e9e5ef
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0454.unit
@@ -0,0 +1,19 @@
+>>> original bug report actually did fit in 80
+class F {
+  List<
+        AVeryLongTypeNameTHatTheUserCannotChange____________> aDescriptiveName__;
+}
+<<<
+class F {
+  List<AVeryLongTypeNameTHatTheUserCannotChange____________> aDescriptiveName__;
+}
+>>>
+class F {
+  List<
+        AVeryLongTypeNameTHatTheUserCannotChange_____________> aDescriptiveName__;
+}
+<<<
+class F {
+  List<AVeryLongTypeNameTHatTheUserCannotChange_____________>
+      aDescriptiveName__;
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0461.stmt b/packages/dart_style/test/regression/0400/0461.stmt
new file mode 100644
index 0000000..adf7b16
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0461.stmt
@@ -0,0 +1,11 @@
+>>> (indent 6)
+      receiver___________.property________.add(
+          new SomeClass___________________.someNamedConstructor_____________________());
+<<<
+      receiver___________.property________.add(new SomeClass___________________
+          .someNamedConstructor_____________________());
+>>> (indent 4)
+    new SomeClass___________________.someNamedConstructor_____________________();
+<<<
+    new SomeClass___________________
+        .someNamedConstructor_____________________();
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0462.unit b/packages/dart_style/test/regression/0400/0462.unit
new file mode 100644
index 0000000..1b728da
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0462.unit
@@ -0,0 +1,33 @@
+>>>
+class Foo {
+  Future<
+      ComponentSettings<
+          BiddingStrategyConfiguration>> _biddingStrategyConfigurationFuture;
+
+  Future<
+      ComponentSettings<
+          BiddingStrategyConfiguration>> get biddingStrategyConfigurationFuture =>
+      _biddingStrategyConfigurationFuture;
+}
+<<<
+class Foo {
+  Future<ComponentSettings<BiddingStrategyConfiguration>>
+      _biddingStrategyConfigurationFuture;
+
+  Future<ComponentSettings<BiddingStrategyConfiguration>>
+      get biddingStrategyConfigurationFuture =>
+          _biddingStrategyConfigurationFuture;
+}
+>>>
+class Foo {
+  HashMap<
+      AnalysisTarget,
+      List<
+          PendingFuture>> get pendingFutureSources_forTesting =>
+      _pendingFutureTargets;
+}
+<<<
+class Foo {
+  HashMap<AnalysisTarget, List<PendingFuture>>
+      get pendingFutureSources_forTesting => _pendingFutureTargets;
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0463.unit b/packages/dart_style/test/regression/0400/0463.unit
new file mode 100644
index 0000000..b307093
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0463.unit
@@ -0,0 +1,22 @@
+>>>
+class FilterBarTest {
+  FilterBarTest() {
+    model = new FilterModel(
+        [const TestComparisonPredicate('test1'), const TestComparisonPredicate('test2')],
+        suggestionProvider,
+        filterTypeProvider,
+        saveFilterAction,
+        hasReadOnlyMode: true,
+        valueEditorProvider: valueEditorProvider);
+  }
+}
+<<<
+class FilterBarTest {
+  FilterBarTest() {
+    model = new FilterModel([
+      const TestComparisonPredicate('test1'),
+      const TestComparisonPredicate('test2')
+    ], suggestionProvider, filterTypeProvider, saveFilterAction,
+        hasReadOnlyMode: true, valueEditorProvider: valueEditorProvider);
+  }
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0465.stmt b/packages/dart_style/test/regression/0400/0465.stmt
new file mode 100644
index 0000000..4b0d988
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0465.stmt
@@ -0,0 +1,32 @@
+>>> (indent 8)
+        if (_shouldReportMissingMember(staticType, staticMethod)) {
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_METHOD,
+              operator, [methodName, staticType.displayName]);
+        } else if (_enableHints &&
+            _shouldReportMissingMember(propagatedType, propagatedMethod) &&
+            !_memberFoundInSubclass(
+                propagatedType.element, methodName, true, false)) {
+          _recordUndefinedToken(
+              propagatedType.element,
+              HintCode.UNDEFINED_METHOD,
+              operator, [methodName, propagatedType.displayName]);
+        }
+<<<
+        if (_shouldReportMissingMember(staticType, staticMethod)) {
+          _recordUndefinedToken(
+              staticType.element,
+              StaticTypeWarningCode.UNDEFINED_METHOD,
+              operator,
+              [methodName, staticType.displayName]);
+        } else if (_enableHints &&
+            _shouldReportMissingMember(propagatedType, propagatedMethod) &&
+            !_memberFoundInSubclass(
+                propagatedType.element, methodName, true, false)) {
+          _recordUndefinedToken(
+              propagatedType.element,
+              HintCode.UNDEFINED_METHOD,
+              operator,
+              [methodName, propagatedType.displayName]);
+        }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0466.unit b/packages/dart_style/test/regression/0400/0466.unit
new file mode 100644
index 0000000..aa7a804
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0466.unit
@@ -0,0 +1,17 @@
+>>> (indent 4)
+    Future get identifier________ async {
+      var id = identifier________.identifier__;
+
+      return identifier_____________[
+          id] ??= await identifier_______.identifier____________________(
+          identifier___________________________.create()..identifier____ = id);
+    }
+<<<
+    Future get identifier________ async {
+      var id = identifier________.identifier__;
+
+      return identifier_____________[id] ??=
+          await identifier_______.identifier____________________(
+              identifier___________________________.create()
+                ..identifier____ = id);
+    }
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0467.unit b/packages/dart_style/test/regression/0400/0467.unit
new file mode 100644
index 0000000..57df4c3
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0467.unit
@@ -0,0 +1,26 @@
+>>>
+class MyElement extends PolymerElement {
+  MyElement.created() : super.created();
+
+  @reflectable
+  void showNodesAndEntryPoints([_, __]) {
+    addAll(
+        'nodesAndEntryPoints',
+        new PolymerDom(
+            this).children.map((child) => '${child.outerHtml} ------> '
+            '${(new PolymerDom(child).getDestinationInsertionPoints()[0] as Element).outerHtml}'));
+  }
+}
+<<<
+class MyElement extends PolymerElement {
+  MyElement.created() : super.created();
+
+  @reflectable
+  void showNodesAndEntryPoints([_, __]) {
+    addAll(
+        'nodesAndEntryPoints',
+        new PolymerDom(this).children.map((child) =>
+            '${child.outerHtml} ------> '
+            '${(new PolymerDom(child).getDestinationInsertionPoints()[0] as Element).outerHtml}'));
+  }
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0474.unit b/packages/dart_style/test/regression/0400/0474.unit
new file mode 100644
index 0000000..5e2dc91
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0474.unit
@@ -0,0 +1,678 @@
+>>>
+Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{
+  'parseCompilationUnit_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseCompilationUnit(arg0)),
+  'parseDirectives_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseDirectives(arg0)),
+  'parseExpression_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseExpression(arg0)),
+  'parseStatement_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseStatement(arg0)),
+  'parseStatements_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseStatements(arg0)),
+  'parseAnnotation_0':
+      new MethodTrampoline(0, (Parser target) => target.parseAnnotation()),
+  'parseArgument_0':
+      new MethodTrampoline(0, (Parser target) => target.parseArgument()),
+  'parseArgumentList_0':
+      new MethodTrampoline(0, (Parser target) => target.parseArgumentList()),
+  'parseBitwiseOrExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseBitwiseOrExpression()),
+  'parseBlock_0':
+      new MethodTrampoline(0, (Parser target) => target.parseBlock()),
+  'parseClassMember_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseClassMember(arg0)),
+  'parseCompilationUnit_0': new MethodTrampoline(
+      0, (Parser target) => target.parseCompilationUnit2()),
+  'parseConditionalExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseConditionalExpression()),
+  'parseConstructorName_0':
+      new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
+  'parseExpression_0':
+      new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
+  'parseExpressionWithoutCascade_0': new MethodTrampoline(
+      0, (Parser target) => target.parseExpressionWithoutCascade()),
+  'parseExtendsClause_0':
+      new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
+  'parseFormalParameterList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseFormalParameterList()),
+  'parseFunctionExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseFunctionExpression()),
+  'parseImplementsClause_0': new MethodTrampoline(
+      0, (Parser target) => target.parseImplementsClause()),
+  'parseLabel_0':
+      new MethodTrampoline(0, (Parser target) => target.parseLabel()),
+  'parseLibraryIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parseLibraryIdentifier()),
+  'parseLogicalOrExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseLogicalOrExpression()),
+  'parseMapLiteralEntry_0':
+      new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()),
+  'parseNormalFormalParameter_0': new MethodTrampoline(
+      0, (Parser target) => target.parseNormalFormalParameter()),
+  'parsePrefixedIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parsePrefixedIdentifier()),
+  'parseReturnType_0':
+      new MethodTrampoline(0, (Parser target) => target.parseReturnType()),
+  'parseSimpleIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parseSimpleIdentifier()),
+  'parseStatement_0':
+      new MethodTrampoline(0, (Parser target) => target.parseStatement2()),
+  'parseStringLiteral_0':
+      new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()),
+  'parseTypeArgumentList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseTypeArgumentList()),
+  'parseTypeName_0':
+      new MethodTrampoline(0, (Parser target) => target.parseTypeName()),
+  'parseTypeParameter_0':
+      new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
+  'parseTypeParameterList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseTypeParameterList()),
+  'parseWithClause_0':
+      new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
+  'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
+  'appendScalarValue_5': new MethodTrampoline(
+      5,
+      (Parser target, arg0, arg1, arg2, arg3, arg4) =>
+          target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
+  'computeStringValue_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._computeStringValue(arg0, arg1, arg2)),
+  'convertToFunctionDeclaration_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
+  'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
+      0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
+  'createSyntheticIdentifier_0':
+      new MethodTrampoline(0, (Parser target) => target._createSyntheticIdentifier()),
+  'createSyntheticKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
+  'createSyntheticStringLiteral_0': new MethodTrampoline(0, (Parser target) => target._createSyntheticStringLiteral()),
+  'createSyntheticToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
+  'ensureAssignable_1': new MethodTrampoline(1, (Parser target, arg0) => target._ensureAssignable(arg0)),
+  'expect_1': new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
+  'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
+  'expectKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._expectKeyword(arg0)),
+  'expectSemicolon_0': new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
+  'findRange_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
+  'getCodeBlockRanges_1': new MethodTrampoline(1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
+  'getEndToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._getEndToken(arg0)),
+  'injectToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._injectToken(arg0)),
+  'isFunctionDeclaration_0': new MethodTrampoline(0, (Parser target) => target._isFunctionDeclaration()),
+  'isFunctionExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._isFunctionExpression(arg0)),
+  'isHexDigit_1': new MethodTrampoline(1, (Parser target, arg0) => target._isHexDigit(arg0)),
+  'isInitializedVariableDeclaration_0': new MethodTrampoline(0, (Parser target) => target._isInitializedVariableDeclaration()),
+  'isLinkText_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
+  'isOperator_1': new MethodTrampoline(1, (Parser target, arg0) => target._isOperator(arg0)),
+  'isSwitchMember_0': new MethodTrampoline(0, (Parser target) => target._isSwitchMember()),
+  'isTypedIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
+  'lockErrorListener_0': new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
+  'matches_1': new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
+  'matchesGt_0': new MethodTrampoline(0, (Parser target) => target._matchesGt()),
+  'matchesIdentifier_0': new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
+  'matchesKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._matchesKeyword(arg0)),
+  'matchesString_1': new MethodTrampoline(1, (Parser target, arg0) => target._matchesString(arg0)),
+  'optional_1': new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
+  'parseAdditiveExpression_0': new MethodTrampoline(0, (Parser target) => target._parseAdditiveExpression()),
+  'parseAssertStatement_0': new MethodTrampoline(0, (Parser target) => target._parseAssertStatement()),
+  'parseAssignableExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseAssignableExpression(arg0)),
+  'parseAssignableSelector_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseAssignableSelector(arg0, arg1)),
+  'parseAwaitExpression_0': new MethodTrampoline(0, (Parser target) => target._parseAwaitExpression()),
+  'parseBitwiseAndExpression_0': new MethodTrampoline(0, (Parser target) => target._parseBitwiseAndExpression()),
+  'parseBitwiseXorExpression_0': new MethodTrampoline(0, (Parser target) => target._parseBitwiseXorExpression()),
+  'parseBreakStatement_0': new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()),
+  'parseCascadeSection_0': new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()),
+  'parseClassDeclaration_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)),
+  'parseClassMembers_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
+  'parseClassTypeAlias_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseClassTypeAlias(arg0, arg1, arg2)),
+  'parseCombinator_0': new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
+  'parseCombinators_0': new MethodTrampoline(0, (Parser target) => target._parseCombinators()),
+  'parseCommentAndMetadata_0': new MethodTrampoline(0, (Parser target) => target._parseCommentAndMetadata()),
+  'parseCommentReference_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)),
+  'parseCommentReferences_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseCommentReferences(arg0)),
+  'parseCompilationUnitMember_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
+  'parseConstExpression_0': new MethodTrampoline(0, (Parser target) => target._parseConstExpression()),
+  'parseConstructor_8': new MethodTrampoline(8, (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
+  'parseConstructorFieldInitializer_0': new MethodTrampoline(0, (Parser target) => target._parseConstructorFieldInitializer()),
+  'parseContinueStatement_0': new MethodTrampoline(0, (Parser target) => target._parseContinueStatement()),
+  'parseDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseDirective(arg0)),
+  'parseDirectives_0': new MethodTrampoline(0, (Parser target) => target._parseDirectives()),
+  'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) => target._parseDocumentationComment()),
+  'parseDoStatement_0': new MethodTrampoline(0, (Parser target) => target._parseDoStatement()),
+  'parseEmptyStatement_0': new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()),
+  'parseEnumConstantDeclaration_0': new MethodTrampoline(0, (Parser target) => target._parseEnumConstantDeclaration()),
+  'parseEnumDeclaration_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)),
+  'parseEqualityExpression_0': new MethodTrampoline(0, (Parser target) => target._parseEqualityExpression()),
+  'parseExportDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseExportDirective(arg0)),
+  'parseExpressionList_0': new MethodTrampoline(0, (Parser target) => target._parseExpressionList()),
+  'parseFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)),
+  'parseFormalParameter_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
+  'parseForStatement_0': new MethodTrampoline(0, (Parser target) => target._parseForStatement()),
+  'parseFunctionBody_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseFunctionBody(arg0, arg1, arg2)),
+  'parseFunctionDeclaration_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseFunctionDeclaration(arg0, arg1, arg2)),
+  'parseFunctionDeclarationStatement_0': new MethodTrampoline(0, (Parser target) => target._parseFunctionDeclarationStatement()),
+  'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
+  'parseFunctionTypeAlias_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseFunctionTypeAlias(arg0, arg1)),
+  'parseGetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseGetter(arg0, arg1, arg2, arg3)),
+  'parseIdentifierList_0': new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
+  'parseIfStatement_0': new MethodTrampoline(0, (Parser target) => target._parseIfStatement()),
+  'parseImportDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseImportDirective(arg0)),
+  'parseInitializedIdentifierList_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
+  'parseInstanceCreationExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
+  'parseLibraryDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
+  'parseLibraryName_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
+  'parseListLiteral_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
+  'parseListOrMapLiteral_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)),
+  'parseLogicalAndExpression_0': new MethodTrampoline(0, (Parser target) => target._parseLogicalAndExpression()),
+  'parseMapLiteral_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
+  'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(7, (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) => target._parseMethodDeclarationAfterParameters(arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
+  'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
+  'parseModifiers_0': new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
+  'parseMultiplicativeExpression_0': new MethodTrampoline(0, (Parser target) => target._parseMultiplicativeExpression()),
+  'parseNativeClause_0': new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
+  'parseNewExpression_0': new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
+  'parseNonLabeledStatement_0': new MethodTrampoline(0, (Parser target) => target._parseNonLabeledStatement()),
+  'parseOperator_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseOperator(arg0, arg1, arg2)),
+  'parseOptionalReturnType_0': new MethodTrampoline(0, (Parser target) => target._parseOptionalReturnType()),
+  'parsePartDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parsePartDirective(arg0)),
+  'parsePostfixExpression_0': new MethodTrampoline(0, (Parser target) => target._parsePostfixExpression()),
+  'parsePrimaryExpression_0': new MethodTrampoline(0, (Parser target) => target._parsePrimaryExpression()),
+  'parseRedirectingConstructorInvocation_0': new MethodTrampoline(0, (Parser target) => target._parseRedirectingConstructorInvocation()),
+  'parseRelationalExpression_0': new MethodTrampoline(0, (Parser target) => target._parseRelationalExpression()),
+  'parseRethrowExpression_0': new MethodTrampoline(0, (Parser target) => target._parseRethrowExpression()),
+  'parseReturnStatement_0': new MethodTrampoline(0, (Parser target) => target._parseReturnStatement()),
+  'parseSetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseSetter(arg0, arg1, arg2, arg3)),
+  'parseShiftExpression_0': new MethodTrampoline(0, (Parser target) => target._parseShiftExpression()),
+  'parseStatementList_0': new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
+  'parseStringInterpolation_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
+  'parseSuperConstructorInvocation_0': new MethodTrampoline(0, (Parser target) => target._parseSuperConstructorInvocation()),
+  'parseSwitchStatement_0': new MethodTrampoline(0, (Parser target) => target._parseSwitchStatement()),
+  'parseSymbolLiteral_0': new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()),
+  'parseThrowExpression_0': new MethodTrampoline(0, (Parser target) => target._parseThrowExpression()),
+  'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(0, (Parser target) => target._parseThrowExpressionWithoutCascade()),
+  'parseTryStatement_0': new MethodTrampoline(0, (Parser target) => target._parseTryStatement()),
+  'parseTypeAlias_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
+  'parseUnaryExpression_0': new MethodTrampoline(0, (Parser target) => target._parseUnaryExpression()),
+  'parseVariableDeclaration_0': new MethodTrampoline(0, (Parser target) => target._parseVariableDeclaration()),
+  'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseVariableDeclarationListAfterMetadata(arg0)),
+  'parseVariableDeclarationListAfterType_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
+  'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseVariableDeclarationStatementAfterMetadata(arg0)),
+  'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
+  'parseWhileStatement_0': new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()),
+  'parseYieldStatement_0': new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()),
+  'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
+  'peekAt_1': new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
+  'reportError_1': new MethodTrampoline(1, (Parser target, arg0) => target._reportError(arg0)),
+  'reportErrorForCurrentToken_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._reportErrorForCurrentToken(arg0, arg1)),
+  'reportErrorForNode_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._reportErrorForNode(arg0, arg1, arg2)),
+  'reportErrorForToken_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._reportErrorForToken(arg0, arg1, arg2)),
+  'skipBlock_0': new MethodTrampoline(0, (Parser target) => target._skipBlock()),
+  'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
+  'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
+  'skipPastMatchingToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
+  'skipPrefixedIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)),
+  'skipReturnType_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipReturnType(arg0)),
+  'skipSimpleIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)),
+  'skipStringInterpolation_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
+  'skipStringLiteral_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipStringLiteral(arg0)),
+  'skipTypeArgumentList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)),
+  'skipTypeName_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeName(arg0)),
+  'skipTypeParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
+  'tokenMatches_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
+  'tokenMatchesIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
+  'tokenMatchesKeyword_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
+  'tokenMatchesString_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
+  'translateCharacter_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._translateCharacter(arg0, arg1, arg2)),
+  'unlockErrorListener_0': new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
+  'validateFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
+  'validateModifiersForClass_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
+  'validateModifiersForConstructor_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
+  'validateModifiersForEnum_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
+  'validateModifiersForField_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
+  'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForFunctionDeclarationStatement(arg0)),
+  'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForGetterOrSetterOrMethod(arg0)),
+  'validateModifiersForOperator_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
+  'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelDeclaration(arg0)),
+  'validateModifiersForTopLevelFunction_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelFunction(arg0)),
+  'validateModifiersForTopLevelVariable_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelVariable(arg0)),
+  'validateModifiersForTypedef_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),
+};
+<<<
+Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{
+  'parseCompilationUnit_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseCompilationUnit(arg0)),
+  'parseDirectives_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseDirectives(arg0)),
+  'parseExpression_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseExpression(arg0)),
+  'parseStatement_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseStatement(arg0)),
+  'parseStatements_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseStatements(arg0)),
+  'parseAnnotation_0':
+      new MethodTrampoline(0, (Parser target) => target.parseAnnotation()),
+  'parseArgument_0':
+      new MethodTrampoline(0, (Parser target) => target.parseArgument()),
+  'parseArgumentList_0':
+      new MethodTrampoline(0, (Parser target) => target.parseArgumentList()),
+  'parseBitwiseOrExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseBitwiseOrExpression()),
+  'parseBlock_0':
+      new MethodTrampoline(0, (Parser target) => target.parseBlock()),
+  'parseClassMember_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target.parseClassMember(arg0)),
+  'parseCompilationUnit_0': new MethodTrampoline(
+      0, (Parser target) => target.parseCompilationUnit2()),
+  'parseConditionalExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseConditionalExpression()),
+  'parseConstructorName_0':
+      new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
+  'parseExpression_0':
+      new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
+  'parseExpressionWithoutCascade_0': new MethodTrampoline(
+      0, (Parser target) => target.parseExpressionWithoutCascade()),
+  'parseExtendsClause_0':
+      new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
+  'parseFormalParameterList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseFormalParameterList()),
+  'parseFunctionExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseFunctionExpression()),
+  'parseImplementsClause_0': new MethodTrampoline(
+      0, (Parser target) => target.parseImplementsClause()),
+  'parseLabel_0':
+      new MethodTrampoline(0, (Parser target) => target.parseLabel()),
+  'parseLibraryIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parseLibraryIdentifier()),
+  'parseLogicalOrExpression_0': new MethodTrampoline(
+      0, (Parser target) => target.parseLogicalOrExpression()),
+  'parseMapLiteralEntry_0':
+      new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()),
+  'parseNormalFormalParameter_0': new MethodTrampoline(
+      0, (Parser target) => target.parseNormalFormalParameter()),
+  'parsePrefixedIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parsePrefixedIdentifier()),
+  'parseReturnType_0':
+      new MethodTrampoline(0, (Parser target) => target.parseReturnType()),
+  'parseSimpleIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target.parseSimpleIdentifier()),
+  'parseStatement_0':
+      new MethodTrampoline(0, (Parser target) => target.parseStatement2()),
+  'parseStringLiteral_0':
+      new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()),
+  'parseTypeArgumentList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseTypeArgumentList()),
+  'parseTypeName_0':
+      new MethodTrampoline(0, (Parser target) => target.parseTypeName()),
+  'parseTypeParameter_0':
+      new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
+  'parseTypeParameterList_0': new MethodTrampoline(
+      0, (Parser target) => target.parseTypeParameterList()),
+  'parseWithClause_0':
+      new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
+  'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
+  'appendScalarValue_5': new MethodTrampoline(
+      5,
+      (Parser target, arg0, arg1, arg2, arg3, arg4) =>
+          target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
+  'computeStringValue_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._computeStringValue(arg0, arg1, arg2)),
+  'convertToFunctionDeclaration_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
+  'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
+      0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
+  'createSyntheticIdentifier_0': new MethodTrampoline(
+      0, (Parser target) => target._createSyntheticIdentifier()),
+  'createSyntheticKeyword_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
+  'createSyntheticStringLiteral_0': new MethodTrampoline(
+      0, (Parser target) => target._createSyntheticStringLiteral()),
+  'createSyntheticToken_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
+  'ensureAssignable_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._ensureAssignable(arg0)),
+  'expect_1':
+      new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
+  'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
+  'expectKeyword_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._expectKeyword(arg0)),
+  'expectSemicolon_0':
+      new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
+  'findRange_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
+  'getCodeBlockRanges_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
+  'getEndToken_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._getEndToken(arg0)),
+  'injectToken_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._injectToken(arg0)),
+  'isFunctionDeclaration_0': new MethodTrampoline(
+      0, (Parser target) => target._isFunctionDeclaration()),
+  'isFunctionExpression_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._isFunctionExpression(arg0)),
+  'isHexDigit_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._isHexDigit(arg0)),
+  'isInitializedVariableDeclaration_0': new MethodTrampoline(
+      0, (Parser target) => target._isInitializedVariableDeclaration()),
+  'isLinkText_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
+  'isOperator_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._isOperator(arg0)),
+  'isSwitchMember_0':
+      new MethodTrampoline(0, (Parser target) => target._isSwitchMember()),
+  'isTypedIdentifier_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
+  'lockErrorListener_0':
+      new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
+  'matches_1':
+      new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
+  'matchesGt_0':
+      new MethodTrampoline(0, (Parser target) => target._matchesGt()),
+  'matchesIdentifier_0':
+      new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
+  'matchesKeyword_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._matchesKeyword(arg0)),
+  'matchesString_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._matchesString(arg0)),
+  'optional_1':
+      new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
+  'parseAdditiveExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseAdditiveExpression()),
+  'parseAssertStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseAssertStatement()),
+  'parseAssignableExpression_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseAssignableExpression(arg0)),
+  'parseAssignableSelector_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._parseAssignableSelector(arg0, arg1)),
+  'parseAwaitExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseAwaitExpression()),
+  'parseBitwiseAndExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseBitwiseAndExpression()),
+  'parseBitwiseXorExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseBitwiseXorExpression()),
+  'parseBreakStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()),
+  'parseCascadeSection_0':
+      new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()),
+  'parseClassDeclaration_2': new MethodTrampoline(2,
+      (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)),
+  'parseClassMembers_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
+  'parseClassTypeAlias_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseClassTypeAlias(arg0, arg1, arg2)),
+  'parseCombinator_0':
+      new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
+  'parseCombinators_0':
+      new MethodTrampoline(0, (Parser target) => target._parseCombinators()),
+  'parseCommentAndMetadata_0': new MethodTrampoline(
+      0, (Parser target) => target._parseCommentAndMetadata()),
+  'parseCommentReference_2': new MethodTrampoline(2,
+      (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)),
+  'parseCommentReferences_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseCommentReferences(arg0)),
+  'parseCompilationUnitMember_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
+  'parseConstExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseConstExpression()),
+  'parseConstructor_8': new MethodTrampoline(
+      8,
+      (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
+          ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
+  'parseConstructorFieldInitializer_0': new MethodTrampoline(
+      0, (Parser target) => target._parseConstructorFieldInitializer()),
+  'parseContinueStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseContinueStatement()),
+  'parseDirective_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseDirective(arg0)),
+  'parseDirectives_0':
+      new MethodTrampoline(0, (Parser target) => target._parseDirectives()),
+  'parseDocumentationComment_0': new MethodTrampoline(
+      0, (Parser target) => target._parseDocumentationComment()),
+  'parseDoStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseDoStatement()),
+  'parseEmptyStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()),
+  'parseEnumConstantDeclaration_0': new MethodTrampoline(
+      0, (Parser target) => target._parseEnumConstantDeclaration()),
+  'parseEnumDeclaration_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)),
+  'parseEqualityExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseEqualityExpression()),
+  'parseExportDirective_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseExportDirective(arg0)),
+  'parseExpressionList_0':
+      new MethodTrampoline(0, (Parser target) => target._parseExpressionList()),
+  'parseFinalConstVarOrType_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)),
+  'parseFormalParameter_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
+  'parseForStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseForStatement()),
+  'parseFunctionBody_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseFunctionBody(arg0, arg1, arg2)),
+  'parseFunctionDeclaration_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseFunctionDeclaration(arg0, arg1, arg2)),
+  'parseFunctionDeclarationStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseFunctionDeclarationStatement()),
+  'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
+  'parseFunctionTypeAlias_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._parseFunctionTypeAlias(arg0, arg1)),
+  'parseGetter_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) =>
+          target._parseGetter(arg0, arg1, arg2, arg3)),
+  'parseIdentifierList_0':
+      new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
+  'parseIfStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseIfStatement()),
+  'parseImportDirective_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseImportDirective(arg0)),
+  'parseInitializedIdentifierList_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) =>
+          target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
+  'parseInstanceCreationExpression_1': new MethodTrampoline(1,
+      (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
+  'parseLibraryDirective_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
+  'parseLibraryName_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
+  'parseListLiteral_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
+  'parseListOrMapLiteral_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)),
+  'parseLogicalAndExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseLogicalAndExpression()),
+  'parseMapLiteral_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
+  'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(
+      7,
+      (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) =>
+          target._parseMethodDeclarationAfterParameters(
+              arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
+  'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) => target
+          ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
+  'parseModifiers_0':
+      new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
+  'parseMultiplicativeExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseMultiplicativeExpression()),
+  'parseNativeClause_0':
+      new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
+  'parseNewExpression_0':
+      new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
+  'parseNonLabeledStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseNonLabeledStatement()),
+  'parseOperator_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseOperator(arg0, arg1, arg2)),
+  'parseOptionalReturnType_0': new MethodTrampoline(
+      0, (Parser target) => target._parseOptionalReturnType()),
+  'parsePartDirective_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parsePartDirective(arg0)),
+  'parsePostfixExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parsePostfixExpression()),
+  'parsePrimaryExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parsePrimaryExpression()),
+  'parseRedirectingConstructorInvocation_0': new MethodTrampoline(
+      0, (Parser target) => target._parseRedirectingConstructorInvocation()),
+  'parseRelationalExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseRelationalExpression()),
+  'parseRethrowExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseRethrowExpression()),
+  'parseReturnStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseReturnStatement()),
+  'parseSetter_4': new MethodTrampoline(
+      4,
+      (Parser target, arg0, arg1, arg2, arg3) =>
+          target._parseSetter(arg0, arg1, arg2, arg3)),
+  'parseShiftExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseShiftExpression()),
+  'parseStatementList_0':
+      new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
+  'parseStringInterpolation_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
+  'parseSuperConstructorInvocation_0': new MethodTrampoline(
+      0, (Parser target) => target._parseSuperConstructorInvocation()),
+  'parseSwitchStatement_0': new MethodTrampoline(
+      0, (Parser target) => target._parseSwitchStatement()),
+  'parseSymbolLiteral_0':
+      new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()),
+  'parseThrowExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseThrowExpression()),
+  'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(
+      0, (Parser target) => target._parseThrowExpressionWithoutCascade()),
+  'parseTryStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseTryStatement()),
+  'parseTypeAlias_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
+  'parseUnaryExpression_0': new MethodTrampoline(
+      0, (Parser target) => target._parseUnaryExpression()),
+  'parseVariableDeclaration_0': new MethodTrampoline(
+      0, (Parser target) => target._parseVariableDeclaration()),
+  'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._parseVariableDeclarationListAfterMetadata(arg0)),
+  'parseVariableDeclarationListAfterType_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
+  'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._parseVariableDeclarationStatementAfterMetadata(arg0)),
+  'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
+  'parseWhileStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()),
+  'parseYieldStatement_0':
+      new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()),
+  'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
+  'peekAt_1':
+      new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
+  'reportError_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._reportError(arg0)),
+  'reportErrorForCurrentToken_2': new MethodTrampoline(
+      2,
+      (Parser target, arg0, arg1) =>
+          target._reportErrorForCurrentToken(arg0, arg1)),
+  'reportErrorForNode_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._reportErrorForNode(arg0, arg1, arg2)),
+  'reportErrorForToken_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._reportErrorForToken(arg0, arg1, arg2)),
+  'skipBlock_0':
+      new MethodTrampoline(0, (Parser target) => target._skipBlock()),
+  'skipFinalConstVarOrType_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
+  'skipFormalParameterList_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
+  'skipPastMatchingToken_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
+  'skipPrefixedIdentifier_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)),
+  'skipReturnType_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipReturnType(arg0)),
+  'skipSimpleIdentifier_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)),
+  'skipStringInterpolation_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
+  'skipStringLiteral_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipStringLiteral(arg0)),
+  'skipTypeArgumentList_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)),
+  'skipTypeName_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipTypeName(arg0)),
+  'skipTypeParameterList_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
+  'tokenMatches_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
+  'tokenMatchesIdentifier_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
+  'tokenMatchesKeyword_2': new MethodTrampoline(2,
+      (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
+  'tokenMatchesString_2': new MethodTrampoline(
+      2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
+  'translateCharacter_3': new MethodTrampoline(
+      3,
+      (Parser target, arg0, arg1, arg2) =>
+          target._translateCharacter(arg0, arg1, arg2)),
+  'unlockErrorListener_0':
+      new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
+  'validateFormalParameterList_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
+  'validateModifiersForClass_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
+  'validateModifiersForConstructor_1': new MethodTrampoline(1,
+      (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
+  'validateModifiersForEnum_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
+  'validateModifiersForField_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
+  'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._validateModifiersForFunctionDeclarationStatement(arg0)),
+  'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._validateModifiersForGetterOrSetterOrMethod(arg0)),
+  'validateModifiersForOperator_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
+  'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._validateModifiersForTopLevelDeclaration(arg0)),
+  'validateModifiersForTopLevelFunction_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._validateModifiersForTopLevelFunction(arg0)),
+  'validateModifiersForTopLevelVariable_1': new MethodTrampoline(
+      1,
+      (Parser target, arg0) =>
+          target._validateModifiersForTopLevelVariable(arg0)),
+  'validateModifiersForTypedef_1': new MethodTrampoline(
+      1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),
+};
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/0400/0475.unit b/packages/dart_style/test/regression/0400/0475.unit
new file mode 100644
index 0000000..0240a3d
--- /dev/null
+++ b/packages/dart_style/test/regression/0400/0475.unit
@@ -0,0 +1,12 @@
+>>>
+class ListResultDescriptor {
+  factory ListResultDescriptor(String name, List<E> defaultValue,
+      {ResultCachingPolicy<
+          List<E>> cachingPolicy}) = ListResultDescriptorImpl<E>;
+}
+<<<
+class ListResultDescriptor {
+  factory ListResultDescriptor(String name, List<E> defaultValue,
+          {ResultCachingPolicy<List<E>> cachingPolicy}) =
+      ListResultDescriptorImpl<E>;
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/other/analysis_server.unit b/packages/dart_style/test/regression/other/analysis_server.unit
index 9e662a7..0c03cfa 100644
--- a/packages/dart_style/test/regression/other/analysis_server.unit
+++ b/packages/dart_style/test/regression/other/analysis_server.unit
@@ -246,4 +246,16 @@
       build(body);
       return irBuilder.makeConstructorDefinition(const [], const []);
     });
-  }
\ No newline at end of file
+  }
+>>> (indent 4)
+    Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+            .variables
+            .variables[0]
+        .name
+        .staticElement;
+<<<
+    Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+        .variables
+        .variables[0]
+        .name
+        .staticElement;
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/other/angular.unit b/packages/dart_style/test/regression/other/angular.unit
new file mode 100644
index 0000000..add59be
--- /dev/null
+++ b/packages/dart_style/test/regression/other/angular.unit
@@ -0,0 +1,45 @@
+>>> (indent 4)
+    main() {
+      it('should expose traverse locals', () {
+        expect(parser('a.b').bind({
+          'a': {'b': 6}
+        }, ContextLocals.wrapper)({
+          'a': {'b': 1}
+        }))
+            .toEqual(1);
+      });
+    }
+<<<
+    main() {
+      it('should expose traverse locals', () {
+        expect(parser('a.b').bind({
+          'a': {'b': 6}
+        }, ContextLocals.wrapper)({
+          'a': {'b': 1}
+        })).toEqual(1);
+      });
+    }
+>>>
+@Component(
+    selector: 'io-controller',
+    template: r'<content></content>',
+    map: const {
+      'attr': '@attr',
+      'expr': '<=>expr',
+      'once': '=>!exprOnce',
+      'ondone': '&onDone',
+      'on-optional': '&onOptional'
+    })
+class IoControllerComponent implements ScopeAware {}
+<<<
+@Component(
+    selector: 'io-controller',
+    template: r'<content></content>',
+    map: const {
+      'attr': '@attr',
+      'expr': '<=>expr',
+      'once': '=>!exprOnce',
+      'ondone': '&onDone',
+      'on-optional': '&onOptional'
+    })
+class IoControllerComponent implements ScopeAware {}
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/other/chains.stmt b/packages/dart_style/test/regression/other/chains.stmt
new file mode 100644
index 0000000..85dc56c
--- /dev/null
+++ b/packages/dart_style/test/regression/other/chains.stmt
@@ -0,0 +1,35 @@
+>>> (indent 2)
+  document.onChange.listen(expectAsync((Delta delta) {
+        observedDeltas.add(delta);
+        if (++observedDeltaCount == 3) applyToNewDocument();
+      }, count: 3));
+<<<
+  document.onChange.listen(expectAsync((Delta delta) {
+    observedDeltas.add(delta);
+    if (++observedDeltaCount == 3) applyToNewDocument();
+  }, count: 3));
+>>> (indent 4)
+    return queryWith(fds, otype, whereClause, whereValues).toList()
+        .catchError((ex, st) {
+      _logger.warning(
+          "Failed loadAllWith($fields, $whereClause, $whereValues)", ex, st);
+      return new Future.error(ex, st);
+    }).then((List<Row> rows) {
+      ;
+    });
+<<<
+    return queryWith(fds, otype, whereClause, whereValues)
+        .toList()
+        .catchError((ex, st) {
+      _logger.warning(
+          "Failed loadAllWith($fields, $whereClause, $whereValues)", ex, st);
+      return new Future.error(ex, st);
+    }).then((List<Row> rows) {
+      ;
+    });
+>>> (indent 4)
+    return _coll.update({"_id": doc["_id"]}, doc, upsert: true)
+        .then((_) => doc);
+<<< TODO(rnystrom): Should split before .then() but map literal splits chain.
+    return _coll
+        .update({"_id": doc["_id"]}, doc, upsert: true).then((_) => doc);
\ No newline at end of file
diff --git a/packages/dart_style/test/regression/other/misc.unit b/packages/dart_style/test/regression/other/misc.unit
new file mode 100644
index 0000000..e6175d7
--- /dev/null
+++ b/packages/dart_style/test/regression/other/misc.unit
@@ -0,0 +1,18 @@
+>>>
+main() {
+  addTask(
+      "publish",
+      createProcessTask("pub",
+          args: ["publish", "-f"], description: "Publishes a New Version"),
+      dependencies: [
+    "version"
+  ]);
+}
+<<<
+main() {
+  addTask(
+      "publish",
+      createProcessTask("pub",
+          args: ["publish", "-f"], description: "Publishes a New Version"),
+      dependencies: ["version"]);
+}
\ No newline at end of file
diff --git a/packages/dart_style/test/selections/._selections.stmt b/packages/dart_style/test/selections/._selections.stmt
deleted file mode 100644
index 9f912de..0000000
--- a/packages/dart_style/test/selections/._selections.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._arrows.unit b/packages/dart_style/test/splitting/._arrows.unit
deleted file mode 100644
index fa01847..0000000
--- a/packages/dart_style/test/splitting/._arrows.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._enums.unit b/packages/dart_style/test/splitting/._enums.unit
deleted file mode 100644
index 3e2969b..0000000
--- a/packages/dart_style/test/splitting/._enums.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._members.unit b/packages/dart_style/test/splitting/._members.unit
deleted file mode 100644
index 473c9f3..0000000
--- a/packages/dart_style/test/splitting/._members.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._parameters.unit b/packages/dart_style/test/splitting/._parameters.unit
deleted file mode 100644
index 51b5117..0000000
--- a/packages/dart_style/test/splitting/._parameters.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._statements.stmt b/packages/dart_style/test/splitting/._statements.stmt
deleted file mode 100644
index 312e399..0000000
--- a/packages/dart_style/test/splitting/._statements.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/._strings.stmt b/packages/dart_style/test/splitting/._strings.stmt
deleted file mode 100644
index e65594f..0000000
--- a/packages/dart_style/test/splitting/._strings.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/splitting/expressions.stmt b/packages/dart_style/test/splitting/expressions.stmt
index 8ac19ef..9136aac 100644
--- a/packages/dart_style/test/splitting/expressions.stmt
+++ b/packages/dart_style/test/splitting/expressions.stmt
@@ -133,4 +133,9 @@
 identifier &&
     identifier &&
     identifier &&
-    identifier;
\ No newline at end of file
+    identifier;
+>>> "." in named constructor
+new VeryLongClassName.veryLongNamedConstructor();
+<<<
+new VeryLongClassName
+    .veryLongNamedConstructor();
\ No newline at end of file
diff --git a/packages/dart_style/test/splitting/invocations.stmt b/packages/dart_style/test/splitting/invocations.stmt
index 3d2a503..952efe9 100644
--- a/packages/dart_style/test/splitting/invocations.stmt
+++ b/packages/dart_style/test/splitting/invocations.stmt
@@ -17,7 +17,7 @@
 <<<
 return call({'type': type, 'id': id})
     .then(deserializeAsset);
->>> allows chained calls on one line with multi-line last argument list
+>>> trailing functions in a chain do not force it to split
 compiler
     .run(script)
     .then((_) {
@@ -27,26 +27,28 @@
 compiler.run(script).then((_) {
   body;
 });
->>> allow inline chains before and after a hard newline
-compiler.a().b((_) {
-  body;
-}).c().d();
+>>> a function in the middle of a chain is indented
+compiler.a().b((_) {body;}).c().d();
 <<<
-compiler.a().b((_) {
-  body;
-}).c().d();
->>> allow an inline chain before a hard newline but not after
-compiler.a().b((_) {
-  body;
-}).somethingLong().somethingLong().somethingLong();
+compiler
+    .a()
+    .b((_) {
+      body;
+    })
+    .c()
+    .d();
+>>> a function in the middle of a chain is indented
+compiler.a().b((_) {body;}).somethingLong().somethingLong().somethingLong();
 <<<
-compiler.a().b((_) {
-  body;
-})
+compiler
+    .a()
+    .b((_) {
+      body;
+    })
     .somethingLong()
     .somethingLong()
     .somethingLong();
->>> allow an inline chain after a hard newline but not before
+>>> a function in the middle of a chain is indented
 compiler.somethingLong().somethingLong().somethingLong((_) {
   body;
 }).a().b();
@@ -55,8 +57,21 @@
     .somethingLong()
     .somethingLong()
     .somethingLong((_) {
+      body;
+    })
+    .a()
+    .b();
+>>> one trailing call does not force function to indent
+compiler.somethingLong().somethingLong().somethingLong((_) {
   body;
-}).a().b();
+}).a();
+<<<
+compiler
+    .somethingLong()
+    .somethingLong()
+    .somethingLong((_) {
+  body;
+}).a();
 >>> nest calls one more than target
 someVeryLongExpression = someVeryLongExpression.someLongMethod();
 <<<
@@ -159,4 +174,109 @@
     ?.method()
     .method()
     ?.method()
-    .method();
\ No newline at end of file
+    .method();
+>>> index in property chain
+someReceiverObject.property1.property2
+        .property3[0]
+    .property4
+    .property5
+    .property6;
+<<<
+someReceiverObject
+    .property1
+    .property2
+    .property3[0]
+    .property4
+    .property5
+    .property6;
+>>> chained indexes
+someReceiverObject.property1.property2
+            .property3[argument]
+        [argument][argument]
+    .property4
+    .property5
+    .property6;
+<<<
+someReceiverObject
+    .property1
+    .property2
+    .property3[argument][argument]
+        [argument]
+    .property4
+    .property5
+    .property6;
+>>> index on method call
+someReceiverObject.property1.property2
+        .method3()[0]
+    .property4
+    .property5
+    .property6;
+<<<
+someReceiverObject.property1.property2
+    .method3()[0]
+    .property4
+    .property5
+    .property6;
+>>> target splits more deeply than method chain
+someTargetFunction(argument, argument, argument).method().method();
+<<<
+someTargetFunction(
+        argument, argument, argument)
+    .method()
+    .method();
+>>> splitting the target forces methods to split
+someVeryLongTargetFunction(argument, argument).one().two();
+<<<
+someVeryLongTargetFunction(
+        argument, argument)
+    .one()
+    .two();
+>>> target splits more deeply than property chain
+someTargetFunction(argument, argument, argument).property.property;
+<<<
+someTargetFunction(
+        argument, argument, argument)
+    .property
+    .property;
+>>> splitting the target forces methods to split
+someVeryLongTargetFunction(argument, argument).one.two;
+<<<
+someVeryLongTargetFunction(
+        argument, argument)
+    .one
+    .two;
+>>> do not split on "." when target is list
+[element, element, element, element, element].someLongMethod();
+<<<
+[
+  element,
+  element,
+  element,
+  element,
+  element
+].someLongMethod();
+>>> do not split on "." when target is map
+{"key": "value", "another": "another value"}.someLongMethod();
+<<<
+{
+  "key": "value",
+  "another": "another value"
+}.someLongMethod();
+>>> do not split on "." when target is function literal passed to method
+method(() {;}).someLongMethod();
+<<<
+method(() {
+  ;
+}).someLongMethod();
+>>> do not split on "." when target is function literal passed to constructor
+new Foo(() {;}).someLongMethod();
+<<<
+new Foo(() {
+  ;
+}).someLongMethod();
+>>> do not split on "." when target is function literal passed to function
+(function)(() {;}).someLongMethod();
+<<<
+(function)(() {
+  ;
+}).someLongMethod();
\ No newline at end of file
diff --git a/packages/dart_style/test/splitting/list_arguments.stmt b/packages/dart_style/test/splitting/list_arguments.stmt
index 8a2b17a..ac10cc1 100644
--- a/packages/dart_style/test/splitting/list_arguments.stmt
+++ b/packages/dart_style/test/splitting/list_arguments.stmt
@@ -273,10 +273,35 @@
   element,
   element
 ]);
->>> nest trailing named if there are non-body named
-longFunctionName(a: argument, b: argument,
+>>> allow leading non-collection to not split
+longFunctionName(a: arg, b: arg,
 c: [element, element, element, element], d: [element, element, element, element]);
 <<<
+longFunctionName(a: arg, b: arg, c: [
+  element,
+  element,
+  element,
+  element
+], d: [
+  element,
+  element,
+  element,
+  element
+]);
+>>> don't allow splitting before first arg while splitting collections
+longFunctionName(
+    a: argument, b: argument, c: [
+  element,
+  element,
+  element,
+  element
+], d: [
+  element,
+  element,
+  element,
+  element
+]);
+<<<
 longFunctionName(
     a: argument,
     b: argument,
@@ -292,6 +317,41 @@
       element,
       element
     ]);
+>>> trailing named arguments that do not split
+longFunctionName(a: [element, element, element, element],
+b: [element, element, element, element], c: argument, d: argument);
+<<<
+longFunctionName(a: [
+  element,
+  element,
+  element,
+  element
+], b: [
+  element,
+  element,
+  element,
+  element
+], c: argument, d: argument);
+>>> trailing named arguments that do split
+longFunctionName(a: [element, element, element, element],
+b: [element, element, element, element], c: argument, d: argument, e: argument);
+<<<
+longFunctionName(
+    a: [
+      element,
+      element,
+      element,
+      element
+    ],
+    b: [
+      element,
+      element,
+      element,
+      element
+    ],
+    c: argument,
+    d: argument,
+    e: argument);
 >>> leading named arguments
 longFunctionName(name1: [element, element], name2: [element, element], name3: argument, name4: argument);
 <<<
@@ -339,4 +399,39 @@
       element,
       element,
       element
-    ]));
\ No newline at end of file
+    ]));
+>>> leading positional collections indent if their args split
+function([[element]],
+[[element]], argument, // comment
+argument);
+<<<
+function(
+    [
+      [element]
+    ],
+    [
+      [element]
+    ],
+    argument, // comment
+    argument);
+>>> trailing positional collections indent if their args split
+function(argument, // comment
+argument, [[element]], [[element]]);
+<<<
+function(
+    argument, // comment
+    argument,
+    [
+      [element]
+    ],
+    [
+      [element]
+    ]);
+>>> comment before collection
+function(argument, // comment
+[[element]]);
+<<<
+function(argument, // comment
+    [
+      [element]
+    ]);
\ No newline at end of file
diff --git a/packages/dart_style/test/splitting/loops.stmt b/packages/dart_style/test/splitting/loops.stmt
index 800e01d..cb62b75 100644
--- a/packages/dart_style/test/splitting/loops.stmt
+++ b/packages/dart_style/test/splitting/loops.stmt
@@ -83,4 +83,31 @@
     longCondition(expression);
     a += 1, b += 1) {
   ;
-}
\ No newline at end of file
+}
+>>> single line for without curlies
+for (i = 0; i < 10; i++) something(i);
+<<<
+for (i = 0; i < 10; i++) something(i);
+>>> multi-line for without curlies
+for (i = 0; i < 10; i++) somethingLonger(i);
+<<<
+for (i = 0; i < 10; i++)
+  somethingLonger(i);
+>>> single line for-in without curlies
+for (i in sequence) something(i);
+<<<
+for (i in sequence) something(i);
+>>> multi-line for-in without curlies
+for (i in sequence) somethingMuchLonger(i);
+<<<
+for (i in sequence)
+  somethingMuchLonger(i);
+>>> single line while without curlies
+while (condition) something(i);
+<<<
+while (condition) something(i);
+>>> multi-line while without curlies
+while (condition) somethingMuchLonger(i);
+<<<
+while (condition)
+  somethingMuchLonger(i);
\ No newline at end of file
diff --git a/packages/dart_style/test/splitting/members.unit b/packages/dart_style/test/splitting/members.unit
index 26ca129..cb59d75 100644
--- a/packages/dart_style/test/splitting/members.unit
+++ b/packages/dart_style/test/splitting/members.unit
@@ -7,4 +7,22 @@
 class Foo {
   Stream methodName(AssetId id) =>
       methodBodyHereItIs;
+}
+>>> can split on getter
+class Foo {
+  VeryLongTypeAnnotation get veryLongGetter => null;
+}
+<<<
+class Foo {
+  VeryLongTypeAnnotation
+      get veryLongGetter => null;
+}
+>>> can split on setter
+class Foo {
+  VeryLongTypeAnnotation set veryLongSetter(v) {}
+}
+<<<
+class Foo {
+  VeryLongTypeAnnotation
+      set veryLongSetter(v) {}
 }
\ No newline at end of file
diff --git a/packages/dart_style/test/splitting/mixed.stmt b/packages/dart_style/test/splitting/mixed.stmt
index 0ef02fd..33cdba4 100644
--- a/packages/dart_style/test/splitting/mixed.stmt
+++ b/packages/dart_style/test/splitting/mixed.stmt
@@ -54,8 +54,10 @@
       .method(argument)
       .method(argument)
       .method(() {
-    body;
-  }).another().another()
+        body;
+      })
+      .another()
+      .another()
 ];
 >>> function inside an argument list
 function(argument, obj.method(argument).method(argument).method(() {body;}).another().another());
@@ -66,8 +68,10 @@
         .method(argument)
         .method(argument)
         .method(() {
-      body;
-    }).another().another());
+          body;
+        })
+        .another()
+        .another());
 >>> unnested function inside nested expression
 function(argument, function(() {;}));
 <<<
@@ -91,14 +95,15 @@
 receiver.firstMethod().next((parameter) => longIdentifier == veryLongIdentifier);
 <<<
 receiver.firstMethod().next(
-    (parameter) => longIdentifier ==
+    (parameter) =>
+        longIdentifier ==
         veryLongIdentifier);
 >>> wrap after =>
 receiver.firstMethod().next(() => veryveryveryverylongIdentifier == veryLongIdentifier);
 <<<
 receiver.firstMethod().next(() =>
     veryveryveryverylongIdentifier ==
-        veryLongIdentifier);
+    veryLongIdentifier);
 >>> wrap at nested binary operator
 receiver.firstMethod().next(longIdentifier == veryLongIdentifier);
 <<<
@@ -193,4 +198,16 @@
 <<<
 longIdentifier +
         (longIdentifier ? 0 : 1) ==
-    identifier;
\ No newline at end of file
+    identifier;
+>>> normal indent before unsplit binary operators in => body
+veryLongFunction() => extremelyLongArgument + argument;
+<<<
+veryLongFunction() =>
+    extremelyLongArgument + argument;
+>>> no extra indent before binary operators in => body
+veryLongFunction() => longArgument + longArgument + longArgument;
+<<<
+veryLongFunction() =>
+    longArgument +
+    longArgument +
+    longArgument;
\ No newline at end of file
diff --git a/packages/dart_style/test/utils.dart b/packages/dart_style/test/utils.dart
index 2c555d0..a2bacc5 100644
--- a/packages/dart_style/test/utils.dart
+++ b/packages/dart_style/test/utils.dart
@@ -5,6 +5,7 @@
 library dart_style.test.utils;
 
 import 'dart:io';
+import 'dart:mirrors';
 
 import 'package:path/path.dart' as p;
 import 'package:scheduled_test/descriptor.dart' as d;
@@ -18,7 +19,12 @@
 ScheduledProcess runFormatter([List<String> args]) {
   if (args == null) args = [];
 
-  var formatterPath = p.join("bin", "format.dart");
+  // Locate the "test" directory. Use mirrors so that this works with the test
+  // package, which loads this suite into an isolate.
+  var testDir = p.dirname(
+      currentMirrorSystem().findLibrary(#dart_style.test.utils).uri.path);
+
+  var formatterPath = p.normalize(p.join(testDir, "../bin/format.dart"));
 
   args.insert(0, formatterPath);
 
diff --git a/packages/dart_style/test/whitespace/._blocks.stmt b/packages/dart_style/test/whitespace/._blocks.stmt
deleted file mode 100644
index bc02ea0..0000000
--- a/packages/dart_style/test/whitespace/._blocks.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._constructors.unit b/packages/dart_style/test/whitespace/._constructors.unit
deleted file mode 100644
index 3e816c7..0000000
--- a/packages/dart_style/test/whitespace/._constructors.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._directives.unit b/packages/dart_style/test/whitespace/._directives.unit
deleted file mode 100644
index 812c891..0000000
--- a/packages/dart_style/test/whitespace/._directives.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._do.stmt b/packages/dart_style/test/whitespace/._do.stmt
deleted file mode 100644
index 7e57633..0000000
--- a/packages/dart_style/test/whitespace/._do.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._enums.unit b/packages/dart_style/test/whitespace/._enums.unit
deleted file mode 100644
index bd3d96f..0000000
--- a/packages/dart_style/test/whitespace/._enums.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._for.stmt b/packages/dart_style/test/whitespace/._for.stmt
deleted file mode 100644
index e045bd1..0000000
--- a/packages/dart_style/test/whitespace/._for.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._methods.unit b/packages/dart_style/test/whitespace/._methods.unit
deleted file mode 100644
index 1f0c542..0000000
--- a/packages/dart_style/test/whitespace/._methods.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._script.unit b/packages/dart_style/test/whitespace/._script.unit
deleted file mode 100644
index 5a17885..0000000
--- a/packages/dart_style/test/whitespace/._script.unit
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._switch.stmt b/packages/dart_style/test/whitespace/._switch.stmt
deleted file mode 100644
index 3fb5c99..0000000
--- a/packages/dart_style/test/whitespace/._switch.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._try.stmt b/packages/dart_style/test/whitespace/._try.stmt
deleted file mode 100644
index 4e6803c..0000000
--- a/packages/dart_style/test/whitespace/._try.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/._while.stmt b/packages/dart_style/test/whitespace/._while.stmt
deleted file mode 100644
index 8fac1ae..0000000
--- a/packages/dart_style/test/whitespace/._while.stmt
+++ /dev/null
Binary files differ
diff --git a/packages/dart_style/test/whitespace/if.stmt b/packages/dart_style/test/whitespace/if.stmt
index 0403400..56019a6 100644
--- a/packages/dart_style/test/whitespace/if.stmt
+++ b/packages/dart_style/test/whitespace/if.stmt
@@ -44,8 +44,10 @@
 >>> single-expression else body
 if(true)print(1);else print(0);
 <<<
-if (true) print(1);
-else print(0);
+if (true)
+  print(1);
+else
+  print(0);
 >>> chained else if
 if (0 == 0) {
   zero = 0;
@@ -61,4 +63,29 @@
   zero = 1;
 } else if (0 == 2) {
   zero = 2;
-}
\ No newline at end of file
+}
+>>> long if without curlies
+if (condition) someLong(argument, another);
+<<<
+if (condition)
+  someLong(argument, another);
+>>> long if else without curlies
+if (condition)
+  someLong(argument, another);
+else
+  anotherLong(argument, another);
+<<<
+if (condition)
+  someLong(argument, another);
+else
+  anotherLong(argument, another);
+>>> long if long else without curlies
+if (condition)
+  someLong(argument, another);
+else
+  anotherLong(argument, another, arg);
+<<<
+if (condition)
+  someLong(argument, another);
+else
+  anotherLong(argument, another, arg);
\ No newline at end of file
diff --git a/packages/dart_style/test/whitespace/metadata.unit b/packages/dart_style/test/whitespace/metadata.unit
index 3932180..292e8c8 100644
--- a/packages/dart_style/test/whitespace/metadata.unit
+++ b/packages/dart_style/test/whitespace/metadata.unit
@@ -14,6 +14,16 @@
 
 @deprecated
 export 'dart:io';
+>>> metadata on part
+@foo part "part.dart";
+<<<
+@foo
+part "part.dart";
+>>> metadata on part of
+@foo part of bar;
+<<<
+@foo
+part of bar;
 >>> force newline before types
 @meta class X {}
 
@@ -215,4 +225,10 @@
 named({@foo bar}) {}
 <<<
 positional([@foo bar]) {}
-named({@foo bar}) {}
\ No newline at end of file
+named({@foo bar}) {}
+>>> split between metadata and parameter indents
+function(@VeryLongMetadataAnnotation longParameter) {}
+<<<
+function(
+    @VeryLongMetadataAnnotation
+        longParameter) {}
\ No newline at end of file
diff --git a/packages/dart_style/tool/grind.dart b/packages/dart_style/tool/grind.dart
new file mode 100644
index 0000000..5a9b1c6
--- /dev/null
+++ b/packages/dart_style/tool/grind.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:grinder/grinder.dart';
+import 'package:pub_semver/pub_semver.dart';
+import 'package:yaml/yaml.dart' as yaml;
+
+/// Matches the version line in dart_style's pubspec.
+final _versionPattern = new RegExp(r"^version: .*$", multiLine: true);
+
+main(args) => grind(args);
+
+@DefaultTask()
+@Task()
+validate() async {
+  // Test it.
+  await new TestRunner().testAsync();
+
+  // Make sure it's warning clean.
+  Analyzer.analyze("bin/format.dart", fatalWarnings: true);
+
+  // Format it.
+  Dart.run("bin/format.dart", arguments: ["-w", "."]);
+}
+
+/// Gets ready to publish a new version of the package.
+///
+/// To publish a version, you need to:
+///
+///   1. Make sure the version in the pubspec is a "-dev" number. This should
+///      already be the case since you've already landed patches that change
+///      the formatter and bumped to that as a consequence.
+///
+///   2. Run this task:
+///
+///         pub run grinder bump
+///
+///   3. Commit the change to a branch.
+///
+///   4. Send it out for review:
+///
+///         git cl upload
+///
+///   5. After the review is complete, land it:
+///
+///         git cl land
+///
+///   6. Tag the commit:
+///
+///         git tag -a "<version>" -m "<version>"
+///         git push origin <version>
+///
+///   7. Publish the package:
+///
+///         pub lish
+@Task()
+@Depends(validate)
+bump() async {
+  // Read the version from the pubspec.
+  var pubspecFile = getFile("pubspec.yaml");
+  var pubspec = pubspecFile.readAsStringSync();
+  var version = new Version.parse(yaml.loadYaml(pubspec)["version"]);
+
+  // Require a "-dev" version since we don't otherwise know what to bump it to.
+  if (!version.isPreRelease) throw "Cannot publish non-dev version $version.";
+
+  // Don't allow versions like "1.2.3-dev+4" because it's not clear if the
+  // user intended the "+4" to be discarded or not.
+  if (version.build.isNotEmpty) throw "Cannot publish build version $version.";
+
+  var bumped = new Version(version.major, version.minor, version.patch);
+
+  // Update the version in the pubspec.
+  pubspec = pubspec.replaceAll(_versionPattern, "version: $bumped");
+  pubspecFile.writeAsStringSync(pubspec);
+
+  // Update the version constant in bin/format.dart.
+  var binFormatFile = getFile("bin/format.dart");
+  var binFormat = binFormatFile.readAsStringSync().replaceAll(
+      new RegExp(r'const version = "[^"]+";'), 'const version = "$bumped";');
+  binFormatFile.writeAsStringSync(binFormat);
+  log("Updated version to '$bumped'.");
+}
diff --git a/packages/intl/CHANGELOG.md b/packages/intl/CHANGELOG.md
index 0469e49..6266a06 100644
--- a/packages/intl/CHANGELOG.md
+++ b/packages/intl/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.12.4+3
+  * update analyzer to '<0.28.0' and fixnum to '<0.11.0'
+
 ## 0.12.4+2
   * update analyzer to '<0.27.0'
 
diff --git a/packages/intl/pubspec.yaml b/packages/intl/pubspec.yaml
index 671a788..33b6ac5 100644
--- a/packages/intl/pubspec.yaml
+++ b/packages/intl/pubspec.yaml
@@ -1,5 +1,5 @@
 name: intl
-version: 0.12.4+2
+version: 0.12.4+3
 author: Dart Team <misc@dartlang.org>
 description: Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues.
 homepage: https://github.com/dart-lang/intl
@@ -7,12 +7,12 @@
   sdk: '>=1.4.0 <2.0.0'
 documentation: http://www.dartdocs.org/documentation/intl/latest
 dependencies:
-  analyzer: '>=0.13.2 <0.27.0'
+  analyzer: '>=0.13.2 <0.28.0'
   args: '>=0.12.1 <0.14.0'
   path: '>=0.9.0 <2.0.0'
   petitparser: '>=1.1.3 <2.0.0'
 dev_dependencies:
-  fixnum: '>=0.9.0 <0.10.0'
+  fixnum: '>=0.9.0 <0.11.0'
   unittest: '>=0.10.0 <0.12.0'
 transformers:
 - $dart2js:
diff --git a/packages/observe/.packages b/packages/observe/.packages
deleted file mode 100644
index c013549..0000000
--- a/packages/observe/.packages
+++ /dev/null
@@ -1,36 +0,0 @@
-# Generate by pub on 2015-08-19 15:03:37.242.
-# This file contains a map from Dart package names to Dart package locations.
-# Dart tools, including the Dart VM and Dart analyzer, rely on the content.
-# AUTO GENERATED - DO NOT EDIT
-analyzer:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/analyzer-0.26.1/lib/
-args:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/args-0.13.2/lib/
-barback:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/barback-0.15.2+6/lib/
-benchmark_harness:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/benchmark_harness-1.0.4/lib/
-browser:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/browser-0.10.0+2/lib/
-charcode:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.0/lib/
-chart:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/chart-1.0.8/lib/
-cli_util:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/cli_util-0.0.1+2/lib/
-code_transformers:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/code_transformers-0.2.9+1/lib/
-collection:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/collection-1.1.1/lib/
-csslib:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/csslib-0.12.1/lib/
-glob:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/glob-1.0.5/lib/
-html:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/html-0.12.1+2/lib/
-intl:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/intl-0.8.10+4/lib/
-logging:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/logging-0.11.1+1/lib/
-meta:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/meta-0.8.8/lib/
-observe:lib/
-package_config:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/package_config-0.1.1/lib/
-path:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/path-1.3.6/lib/
-plugin:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/plugin-0.1.0/lib/
-pool:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/pool-1.1.0/lib/
-smoke:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/smoke-0.3.5/lib/
-source_maps:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.1/lib/
-source_span:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/source_span-1.1.3/lib/
-stack_trace:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.4.1/lib/
-string_scanner:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/string_scanner-0.1.3+1/lib/
-unittest:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/unittest-0.11.6+1/lib/
-utf:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+2/lib/
-watcher:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7/lib/
-when:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/when-0.2.0/lib/
-which:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/which-0.1.3/lib/
-yaml:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.3/lib/
diff --git a/packages/observe/CHANGELOG.md b/packages/observe/CHANGELOG.md
index 3f8a16a..9b7a559 100644
--- a/packages/observe/CHANGELOG.md
+++ b/packages/observe/CHANGELOG.md
@@ -1,3 +1,7 @@
+#### 0.13.1+3
+
+ * Sorting an already sorted list will no longer yield new change notifications.
+
 #### 0.13.1+2
 
  * Update to analyzer '<0.27.0'
diff --git a/packages/observe/lib/src/observable_list.dart b/packages/observe/lib/src/observable_list.dart
index 912c4fc..9d09b38 100644
--- a/packages/observe/lib/src/observable_list.dart
+++ b/packages/observe/lib/src/observable_list.dart
@@ -91,7 +91,7 @@
 
   @reflectable void operator []=(int index, E value) {
     var oldValue = _list[index];
-    if (hasListObservers) {
+    if (hasListObservers && oldValue != value) {
       _recordChange(new ListChangeRecord(this, index, addedCount: 1,
           removed: [oldValue]));
     }
diff --git a/packages/observe/pubspec.yaml b/packages/observe/pubspec.yaml
index b9c5c84..29829e2 100644
--- a/packages/observe/pubspec.yaml
+++ b/packages/observe/pubspec.yaml
@@ -1,5 +1,5 @@
 name: observe
-version: 0.13.1+2
+version: 0.13.1+3
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 description: >
   Observable properties and objects for use in template_binding.
diff --git a/packages/observe/test/observable_list_test.dart b/packages/observe/test/observable_list_test.dart
index 81ca45f..adc6e40 100644
--- a/packages/observe/test/observable_list_test.dart
+++ b/packages/observe/test/observable_list_test.dart
@@ -269,6 +269,19 @@
       });
     });
 
+    test('sort of 2 elements', () {
+      var list = toObservable([3, 1]);
+      // Dummy listener to record changes.
+      // TODO(jmesserly): should we just record changes always, to support the sync api?
+      sub = list.listChanges.listen((records) => null);
+      list.sort();
+      expect(list.deliverListChanges(), true);
+      list.sort();
+      expect(list.deliverListChanges(), false);
+      list.sort();
+      expect(list.deliverListChanges(), false);
+    });
+    
     test('clear', () {
       list.clear();
       expect(list, []);
@@ -292,3 +305,4 @@
 
 _change(index, {removed: const [], addedCount: 0}) => new ListChangeRecord(
     list, index, removed: removed, addedCount: addedCount);
+
diff --git a/packages/path/.gitignore b/packages/path/.gitignore
index 388eff0..7dbf035 100644
--- a/packages/path/.gitignore
+++ b/packages/path/.gitignore
@@ -3,6 +3,7 @@
 .pub/
 build/
 packages
+.packages
 
 # Or the files created by dart2js.
 *.dart.js
diff --git a/packages/path/.status b/packages/path/.status
deleted file mode 100644
index bfc58fc..0000000
--- a/packages/path/.status
+++ /dev/null
@@ -1,21 +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.
-
-# Skip non-test files ending with "_test".
-packages/*: Skip
-*/packages/*: Skip
-*/*/packages/*: Skip
-*/*/*/packages/*: Skip
-*/*/*/*packages/*: Skip
-*/*/*/*/*packages/*: Skip
-
-# Only run tests from the build directory, since we don't care about the
-# difference between transformed an untransformed code.
-test/*: Skip
-
-[ $browser ]
-build/test/io_test: Fail, OK # Uses dart:io.
-
-[ $runtime == vm ]
-build/test/browser_test: Fail, OK # Uses dart:html
diff --git a/packages/path/.test_config b/packages/path/.test_config
new file mode 100644
index 0000000..412fc5c
--- /dev/null
+++ b/packages/path/.test_config
@@ -0,0 +1,3 @@
+{
+  "test_package": true
+}
\ No newline at end of file
diff --git a/packages/path/CHANGELOG.md b/packages/path/CHANGELOG.md
index 457be80..44090f6 100644
--- a/packages/path/CHANGELOG.md
+++ b/packages/path/CHANGELOG.md
@@ -1,3 +1,23 @@
+## 1.3.9
+
+* Further improve the performance of `isWithin()` when paths contain `/.`
+  sequences that aren't `/../`.
+
+## 1.3.8
+
+* Improve the performance of `isWithin()` when the paths don't contain
+  asymmetrical `.` or `..` components.
+
+* Improve the performance of `relative()` when `from` is `null` and the path is
+  already relative.
+
+* Improve the performance of `current` when the current directory hasn't
+  changed.
+
+## 1.3.7
+
+* Improve the performance of `absolute()` and `normalize()`.
+
 ## 1.3.6
 
 * Ensure that `path.toUri` preserves trailing slashes for relative paths.
diff --git a/packages/path/benchmark/benchmark.dart b/packages/path/benchmark/benchmark.dart
index 419eee0..4285e65 100644
--- a/packages/path/benchmark/benchmark.dart
+++ b/packages/path/benchmark/benchmark.dart
@@ -21,18 +21,48 @@
   print("$name: ${count / sw.elapsedMicroseconds} iter/us (${sw.elapsed})");
 }
 
+void runBenchmarkTwoArgs(String name, Function func, List files) {
+  // Warmup.
+  for (int i = 0; i < 1000; i++) {
+    for (var file1 in files) {
+      for (var file2 in files) {
+        func(file1, file2);
+      }
+    }
+  }
+
+  var count = 10000;
+  var sw = new Stopwatch()..start();
+  for (int i = 0; i < count; i++) {
+    for (var file1 in files) {
+      for (var file2 in files) {
+        func(file1, file2);
+      }
+    }
+  }
+  print("$name: ${count / sw.elapsedMicroseconds} iter/us (${sw.elapsed})");
+}
+
 main(args) {
   for (var style in [path.Style.posix, path.Style.url, path.Style.windows]) {
     var context = new path.Context(style: style);
     var files = COMMON_PATHS.toList()..addAll(STYLE_PATHS[style]);
 
-    void benchmark(name, func) {
+    benchmark(name, func) {
       name = style.name + '-' + name;
       if (args.isEmpty || args.any((arg) => name.contains(arg))) {
         runBenchmark(name, func, files);
       }
     }
 
+    benchmarkTwoArgs(name, func) {
+      name = style.name + '-' + name + '-two';
+      if (args.isEmpty || args.any((arg) => name.contains(arg))) {
+        runBenchmarkTwoArgs(name, func, files);
+      }
+    }
+
+    benchmark('absolute', context.absolute);
     benchmark('basename', context.basename);
     benchmark('basenameWithoutExtension', context.basenameWithoutExtension);
     benchmark('dirname', context.dirname);
@@ -43,8 +73,14 @@
     benchmark('isRootRelative', context.isRootRelative);
     benchmark('normalize', context.normalize);
     benchmark('relative', context.relative);
+    benchmarkTwoArgs('relative', context.relative);
     benchmark('toUri', context.toUri);
     benchmark('prettyUri', context.prettyUri);
+    benchmarkTwoArgs('isWithin', context.isWithin);
+  }
+
+  if (args.isEmpty || args.any((arg) => arg == 'current')) {
+    runBenchmark('current', (_) => path.current, [null]);
   }
 }
 
diff --git a/packages/path/lib/path.dart b/packages/path/lib/path.dart
index af9efe5..93fe67e 100644
--- a/packages/path/lib/path.dart
+++ b/packages/path/lib/path.dart
@@ -79,17 +79,36 @@
 /// In the browser, this means the current URL, without the last file segment.
 String get current {
   var uri = Uri.base;
+
+  // Converting the base URI to a file path is pretty slow, and the base URI
+  // rarely changes in practice, so we cache the result here.
+  if (uri == _currentUriBase) return _current;
+  _currentUriBase = uri;
+
   if (Style.platform == Style.url) {
-    return uri.resolve('.').toString();
+    _current = uri.resolve('.').toString();
+    return _current;
   } else {
     var path = uri.toFilePath();
     // Remove trailing '/' or '\'.
-    int lastIndex = path.length - 1;
+    var lastIndex = path.length - 1;
     assert(path[lastIndex] == '/' || path[lastIndex] == '\\');
-    return path.substring(0, lastIndex);
+    _current = path.substring(0, lastIndex);
+    return _current;
   }
 }
 
+/// The last value returned by [Uri.base].
+///
+/// This is used to cache the current working directory.
+Uri _currentUriBase;
+
+/// The last known value of the current working directory.
+///
+/// This is cached because [current] is called frequently but rarely actually
+/// changes.
+String _current;
+
 /// Gets the path separator for the current platform. This is `\` on Windows
 /// and `/` on other platforms (including the browser).
 String get separator => context.separator;
diff --git a/packages/path/lib/src/context.dart b/packages/path/lib/src/context.dart
index db055a1..d10a29f 100644
--- a/packages/path/lib/src/context.dart
+++ b/packages/path/lib/src/context.dart
@@ -4,6 +4,7 @@
 
 library path.context;
 
+import 'characters.dart' as chars;
 import 'internal_style.dart';
 import 'style.dart';
 import 'parsed_path.dart';
@@ -73,6 +74,15 @@
   /// If [current] isn't absolute, this won't return an absolute path.
   String absolute(String part1, [String part2, String part3, String part4,
       String part5, String part6, String part7]) {
+    _validateArgList(
+        "absolute", [part1, part2, part3, part4, part5, part6, part7]);
+
+    // If there's a single absolute path, just return it. This is a lot faster
+    // for the common case of `p.absolute(path)`.
+    if (part2 == null && isAbsolute(part1) && !isRootRelative(part1)) {
+      return part1;
+    }
+
     return join(current, part1, part2, part3, part4, part5, part6, part7);
   }
 
@@ -295,11 +305,79 @@
   ///
   ///     context.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
   String normalize(String path) {
+    if (!_needsNormalization(path)) return path;
+
     var parsed = _parse(path);
     parsed.normalize();
     return parsed.toString();
   }
 
+  /// Returns whether [path] needs to be normalized.
+  bool _needsNormalization(String path) {
+    var start = 0;
+    var codeUnits = path.codeUnits;
+    var previousPrevious;
+    var previous;
+
+    // Skip past the root before we start looking for snippets that need
+    // normalization. We want to normalize "//", but not when it's part of
+    // "http://".
+    var root = style.rootLength(path);
+    if (root != 0) {
+      start = root;
+      previous = chars.SLASH;
+
+      // On Windows, the root still needs to be normalized if it contains a
+      // forward slash.
+      if (style == Style.windows) {
+        for (var i = 0; i < root; i++) {
+          if (codeUnits[i] == chars.SLASH) return true;
+        }
+      }
+    }
+
+    for (var i = start; i < codeUnits.length; i++) {
+      var codeUnit = codeUnits[i];
+      if (style.isSeparator(codeUnit)) {
+        // Forward slashes in Windows paths are normalized to backslashes.
+        if (style == Style.windows && codeUnit == chars.SLASH) return true;
+
+        // Multiple separators are normalized to single separators.
+        if (previous != null && style.isSeparator(previous)) return true;
+
+        // Single dots and double dots are normalized to directory traversals.
+        //
+        // This can return false positives for ".../", but that's unlikely
+        // enough that it's probably not going to cause performance issues.
+        if (previous == chars.PERIOD &&
+            (previousPrevious == null ||
+             previousPrevious == chars.PERIOD ||
+             style.isSeparator(previousPrevious))) {
+          return true;
+        }
+      }
+
+      previousPrevious = previous;
+      previous = codeUnit;
+    }
+
+    // Empty paths are normalized to ".".
+    if (previous == null) return true;
+
+    // Trailing separators are removed.
+    if (style.isSeparator(previous)) return true;
+
+    // Single dots and double dots are normalized to directory traversals.
+    if (previous == chars.PERIOD &&
+        (previousPrevious == null ||
+         previousPrevious == chars.SLASH ||
+         previousPrevious == chars.PERIOD)) {
+      return true;
+    }
+
+    return false;
+  }
+
   /// Attempts to convert [path] to an equivalent relative path relative to
   /// [root].
   ///
@@ -333,13 +411,10 @@
   /// "/", no path can be determined. In this case, a [PathException] will be
   /// thrown.
   String relative(String path, {String from}) {
-    // Avoid calling [current] since it is slow and calling join() when
-    // [from] is absolute does nothing.
-    if (from == null) {
-      from = current;
-    } else if (this.isRelative(from) || this.isRootRelative(from)) {
-      from = this.join(current, from);
-    }
+    // Avoid expensive computation if the path is already relative.
+    if (from == null && this.isRelative(path)) return this.normalize(path);
+
+    from = from == null ? current : absolute(from);
 
     // We can't determine the path from a relative path to an absolute path.
     if (this.isRelative(from) && this.isAbsolute(path)) {
@@ -425,6 +500,31 @@
   ///     path.isWithin('/root/path', '/root/other'); // -> false
   ///     path.isWithin('/root/path', '/root/path'); // -> false
   bool isWithin(String parent, String child) {
+    // Make both paths the same level of relative. We're only able to do the
+    // quick comparison if both paths are in the same format, and making a path
+    // absolute is faster than making it relative.
+    var parentIsAbsolute = isAbsolute(parent);
+    var childIsAbsolute = isAbsolute(child);
+    if (parentIsAbsolute && !childIsAbsolute) {
+      child = absolute(child);
+      if (style.isRootRelative(parent)) parent = absolute(parent);
+    } else if (childIsAbsolute && !parentIsAbsolute) {
+      parent = absolute(parent);
+      if (style.isRootRelative(child)) child = absolute(child);
+    } else if (childIsAbsolute && parentIsAbsolute) {
+      var childIsRootRelative = style.isRootRelative(child);
+      var parentIsRootRelative = style.isRootRelative(parent);
+
+      if (childIsRootRelative && !parentIsRootRelative) {
+        child = absolute(child);
+      } else if (parentIsRootRelative && !childIsRootRelative) {
+        parent = absolute(parent);
+      }
+    }
+
+    var fastResult = _isWithinFast(parent, child);
+    if (fastResult != null) return fastResult;
+
     var relative;
     try {
       relative = this.relative(child, from: parent);
@@ -440,6 +540,259 @@
         parts.first != '.';
   }
 
+  /// An optimized implementation of [isWithin] that doesn't handle a few
+  /// complex cases.
+  bool _isWithinFast(String parent, String child) {
+    // Normally we just bail when we see "." path components, but we can handle
+    // a single dot easily enough.
+    if (parent == '.') parent = '';
+
+    var parentRootLength = style.rootLength(parent);
+    var childRootLength = style.rootLength(child);
+
+    // If the roots aren't the same length, we know both paths are absolute or
+    // both are root-relative, and thus that the roots are meaningfully
+    // different.
+    //
+    //     isWithin("C:/bar", "//foo/bar/baz") //=> false
+    //     isWithin("http://example.com/", "http://google.com/bar") //=> false
+    if (parentRootLength != childRootLength) return false;
+
+    var parentCodeUnits = parent.codeUnits;
+    var childCodeUnits = child.codeUnits;
+
+    // Make sure that the roots are textually the same as well.
+    //
+    //     isWithin("C:/bar", "D:/bar/baz") //=> false
+    //     isWithin("http://example.com/", "http://example.org/bar") //=> false
+    for (var i = 0; i < parentRootLength; i++) {
+      var parentCodeUnit = parentCodeUnits[i];
+      var childCodeUnit = childCodeUnits[i];
+      if (parentCodeUnit == childCodeUnit) continue;
+
+      // If both code units are separators, that's fine too.
+      //
+      //     isWithin("C:/", r"C:\foo") //=> true
+      if (!style.isSeparator(parentCodeUnit) ||
+          !style.isSeparator(childCodeUnit)) {
+        return false;
+      }
+    }
+
+    // Start by considering the last code unit as a separator, since
+    // semantically we're starting at a new path component even if we're
+    // comparing relative paths.
+    var lastCodeUnit = chars.SLASH;
+
+    // Iterate through both paths as long as they're semantically identical.
+    var parentIndex = parentRootLength;
+    var childIndex = childRootLength;
+    while (parentIndex < parent.length && childIndex < child.length) {
+      var parentCodeUnit = parentCodeUnits[parentIndex];
+      var childCodeUnit = childCodeUnits[childIndex];
+      if (parentCodeUnit == childCodeUnit) {
+        lastCodeUnit = parentCodeUnit;
+        parentIndex++;
+        childIndex++;
+        continue;
+      }
+
+      // Different separators are considered identical.
+      var parentIsSeparator = style.isSeparator(parentCodeUnit);
+      var childIsSeparator = style.isSeparator(childCodeUnit);
+      if (parentIsSeparator && childIsSeparator) {
+        lastCodeUnit = parentCodeUnit;
+        parentIndex++;
+        childIndex++;
+        continue;
+      }
+
+      // Ignore multiple separators in a row.
+      if (parentIsSeparator && style.isSeparator(lastCodeUnit)) {
+        parentIndex++;
+        continue;
+      } else if (childIsSeparator && style.isSeparator(lastCodeUnit)) {
+        childIndex++;
+        continue;
+      }
+
+      if (parentCodeUnit == chars.PERIOD) {
+        // If a dot comes after a separator, it may be a directory traversal
+        // operator. To check that, we need to know if it's followed by either
+        // "/" or "./". Otherwise, it's just a normal non-matching character.
+        //
+        //     isWithin("foo/./bar", "foo/bar/baz") //=> true
+        //     isWithin("foo/bar/../baz", "foo/bar/.foo") //=> false
+        if (style.isSeparator(lastCodeUnit)) {
+          parentIndex++;
+
+          // We've hit "/." at the end of the parent path, which we can ignore,
+          // since the paths were equivalent up to this point.
+          if (parentIndex == parent.length) break;
+          parentCodeUnit = parentCodeUnits[parentIndex];
+
+          // We've hit "/./", which we can ignore.
+          if (style.isSeparator(parentCodeUnit)) {
+            parentIndex++;
+            continue;
+          }
+
+          // We've hit "/..", which may be a directory traversal operator that
+          // we can't handle on the fast track.
+          if (parentCodeUnit == chars.PERIOD) {
+            parentIndex++;
+            if (parentIndex == parent.length ||
+                style.isSeparator(parentCodeUnits[parentIndex])) {
+              return null;
+            }
+          }
+        }
+
+        // If this isn't a directory traversal, fall through so we hit the
+        // normal handling for mismatched paths.
+      }
+
+      // This is the same logic as above, but for the child path instead of the
+      // parent.
+      if (childCodeUnit == chars.PERIOD) {
+        if (style.isSeparator(lastCodeUnit)) {
+          childIndex++;
+          if (childIndex == child.length) break;
+          childCodeUnit = childCodeUnits[childIndex];
+
+          if (style.isSeparator(childCodeUnit)) {
+            childIndex++;
+            continue;
+          }
+
+          if (childCodeUnit == chars.PERIOD) {
+            childIndex++;
+            if (childIndex == child.length ||
+                style.isSeparator(childCodeUnits[childIndex])) {
+              return null;
+            }
+          }
+        }
+      }
+
+      // If we're here, we've hit two non-matching, non-significant characters.
+      // As long as the remainders of the two paths don't have any unresolved
+      // ".." components, we can be confident that [child] is not within
+      // [parent].
+      var childDirection = _pathDirection(childCodeUnits, childIndex);
+      if (childDirection != _PathDirection.belowRoot) return null;
+      var parentDirection = _pathDirection(parentCodeUnits, parentIndex);
+      if (parentDirection != _PathDirection.belowRoot) return null;
+
+      return false;
+    }
+
+    // If the child is shorter than the parent, it's probably not within the
+    // parent. The only exception is if the parent has some weird ".." stuff
+    // going on, in which case we do the slow check.
+    //
+    //     isWithin("foo/bar/baz", "foo/bar") //=> false
+    //     isWithin("foo/bar/baz/../..", "foo/bar") //=> true
+    if (childIndex == child.length) {
+      var direction = _pathDirection(parentCodeUnits, parentIndex);
+      return direction == _PathDirection.aboveRoot ? null : false;
+    }
+
+    // We've reached the end of the parent path, which means it's time to make a
+    // decision. Before we do, though, we'll check the rest of the child to see
+    // what that tells us.
+    var direction = _pathDirection(childCodeUnits, childIndex);
+
+    // If there are no more components in the child, then it's the same as
+    // the parent, not within it.
+    //
+    //     isWithin("foo/bar", "foo/bar") //=> false
+    //     isWithin("foo/bar", "foo/bar//") //=> false
+    if (direction == _PathDirection.atRoot) return false;
+
+    // If there are unresolved ".." components in the child, no decision we make
+    // will be valid. We'll abort and do the slow check instead.
+    //
+    //     isWithin("foo/bar", "foo/bar/..") //=> false
+    //     isWithin("foo/bar", "foo/bar/baz/bang/../../..") //=> false
+    //     isWithin("foo/bar", "foo/bar/baz/bang/../../../bar/baz") //=> true
+    if (direction == _PathDirection.aboveRoot) return null;
+
+    // The child is within the parent if and only if we're on a separator
+    // boundary.
+    //
+    //     isWithin("foo/bar", "foo/bar/baz") //=> true
+    //     isWithin("foo/bar/", "foo/bar/baz") //=> true
+    //     isWithin("foo/bar", "foo/barbaz") //=> false
+    return style.isSeparator(childCodeUnits[childIndex]) ||
+        style.isSeparator(lastCodeUnit);
+  }
+
+  // Returns a [_PathDirection] describing the path represented by [codeUnits]
+  // after [index].
+  //
+  // This ignores leading separators.
+  //
+  //     pathDirection("foo") //=> below root
+  //     pathDirection("foo/bar/../baz") //=> below root
+  //     pathDirection("//foo/bar/baz") //=> below root
+  //     pathDirection("/") //=> at root
+  //     pathDirection("foo/..") //=> at root
+  //     pathDirection("foo/../baz") //=> reaches root
+  //     pathDirection("foo/../..") //=> above root
+  //     pathDirection("foo/../../foo/bar/baz") //=> above root
+  _PathDirection _pathDirection(List<int> codeUnits, int index) {
+    var depth = 0;
+    var reachedRoot = false;
+    var i = index;
+    while (i < codeUnits.length) {
+      // Ignore initial separators or doubled separators.
+      while (i < codeUnits.length && style.isSeparator(codeUnits[i])) {
+        i++;
+      }
+
+      // If we're at the end, stop.
+      if (i == codeUnits.length) break;
+
+      // Move through the path component to the next separator.
+      var start = i;
+      while (i < codeUnits.length && !style.isSeparator(codeUnits[i])) {
+        i++;
+      }
+
+      // See if the path component is ".", "..", or a name.
+      if (i - start == 1 && codeUnits[start] == chars.PERIOD) {
+        // Don't change the depth.
+      } else if (i - start == 2 &&
+          codeUnits[start] == chars.PERIOD &&
+          codeUnits[start + 1] == chars.PERIOD) {
+        // ".." backs out a directory.
+        depth--;
+
+        // If we work back beyond the root, stop.
+        if (depth < 0) break;
+
+        // Record that we reached the root so we don't return
+        // [_PathDirection.belowRoot].
+        if (depth == 0) reachedRoot = true;
+      } else {
+        // Step inside a directory.
+        depth++;
+      }
+
+      // If we're at the end, stop.
+      if (i == codeUnits.length) break;
+
+      // Move past the separator.
+      i++;
+    }
+
+    if (depth < 0) return _PathDirection.aboveRoot;
+    if (depth == 0) return _PathDirection.atRoot;
+    if (reachedRoot) return _PathDirection.reachesRoot;
+    return _PathDirection.belowRoot;
+  }
+
   /// Removes a trailing extension from the last part of [path].
   ///
   ///     context.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
@@ -572,3 +925,30 @@
     throw new ArgumentError(message.toString());
   }
 }
+
+/// An enum of possible return values for [Context._pathDirection].
+class _PathDirection {
+  /// The path contains enough ".." components that at some point it reaches
+  /// above its original root.
+  ///
+  /// Note that this applies even if the path ends beneath its original root. It
+  /// takes precendence over any other return values that may apple.
+  static const aboveRoot = const _PathDirection("above root");
+
+  /// The path contains enough ".." components that it ends at its original
+  /// root.
+  static const atRoot = const _PathDirection("at root");
+
+  /// The path contains enough ".." components that at some point it reaches its
+  /// original root, but it ends beneath that root.
+  static const reachesRoot = const _PathDirection("reaches root");
+
+  /// The path never reaches to or above its original root.
+  static const belowRoot = const _PathDirection("below root");
+
+  final String name;
+
+  const _PathDirection(this.name);
+
+  String toString() => name;
+}
diff --git a/packages/path/pubspec.yaml b/packages/path/pubspec.yaml
index 6ba3a15..fb21d20 100644
--- a/packages/path/pubspec.yaml
+++ b/packages/path/pubspec.yaml
@@ -1,5 +1,5 @@
 name: path
-version: 1.3.6
+version: 1.3.9
 author: Dart Team <misc@dartlang.org>
 description: >
  A string-based path manipulation library. All of the path operations you know
@@ -7,6 +7,6 @@
  machines.
 homepage: http://github.com/dart-lang/path
 dev_dependencies:
-  unittest: ">=0.9.0 <0.12.0"
+  test: ">=0.12.0 <0.13.0"
 environment:
   sdk: ">=1.0.0 <2.0.0"
diff --git a/packages/path/test/browser_test.dart b/packages/path/test/browser_test.dart
index 0b56c7a..b329146 100644
--- a/packages/path/test/browser_test.dart
+++ b/packages/path/test/browser_test.dart
@@ -2,15 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+@TestOn('browser')
+
 import 'dart:html';
 
-import 'package:unittest/unittest.dart';
-import 'package:unittest/html_config.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 main() {
-  useHtmlConfiguration();
-
   group('new Context()', () {
     test('uses the window location if root and style are omitted', () {
       var context = new path.Context();
diff --git a/packages/path/test/io_test.dart b/packages/path/test/io_test.dart
index e855522..f15f82d 100644
--- a/packages/path/test/io_test.dart
+++ b/packages/path/test/io_test.dart
@@ -2,9 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+@TestOn('vm')
+
 import 'dart:io' as io;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 main() {
diff --git a/packages/path/test/path_test.dart b/packages/path/test/path_test.dart
index 19397cf..b45f8dc 100644
--- a/packages/path/test/path_test.dart
+++ b/packages/path/test/path_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 main() {
diff --git a/packages/path/test/posix_test.dart b/packages/path/test/posix_test.dart
index 2368d99..afd6b94 100644
--- a/packages/path/test/posix_test.dart
+++ b/packages/path/test/posix_test.dart
@@ -4,7 +4,7 @@
 
 library path.test.posix_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 import 'utils.dart';
@@ -419,6 +419,19 @@
       expect(context.isWithin('baz', '/root/path/bang/baz'), isFalse);
     });
 
+    test('complex cases', () {
+      expect(context.isWithin('foo/./bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo//bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo/qux/../bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/../..'), isFalse);
+      expect(context.isWithin('foo/bar', 'foo/bar///'), isFalse);
+      expect(context.isWithin('foo/.bar', 'foo/.bar/baz'), isTrue);
+      expect(context.isWithin('foo/./bar', 'foo/.bar/baz'), isFalse);
+      expect(context.isWithin('foo/..bar', 'foo/..bar/baz'), isTrue);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/..'), isFalse);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/../qux'), isTrue);
+    });
+
     test('from a relative root', () {
       var r = new path.Context(style: path.Style.posix, current: 'foo/bar');
       expect(r.isWithin('.', 'a/b/c'), isTrue);
diff --git a/packages/path/test/relative_test.dart b/packages/path/test/relative_test.dart
index 57a9046..3cf02dc 100644
--- a/packages/path/test/relative_test.dart
+++ b/packages/path/test/relative_test.dart
@@ -4,7 +4,7 @@
 //
 // Test "relative" on all styles of path.Context, on all platforms.
 
-import "package:unittest/unittest.dart";
+import "package:test/test.dart";
 import "package:path/path.dart" as path;
 
 import "utils.dart";
diff --git a/packages/path/test/url_test.dart b/packages/path/test/url_test.dart
index 854e19a..c81893a 100644
--- a/packages/path/test/url_test.dart
+++ b/packages/path/test/url_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 main() {
@@ -629,6 +629,31 @@
           isFalse);
     });
 
+    test('complex cases', () {
+      expect(context.isWithin('foo/./bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo//bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo/qux/../bar', 'foo/bar/baz'), isTrue);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/../..'), isFalse);
+      expect(context.isWithin('foo/bar', 'foo/bar///'), isFalse);
+      expect(context.isWithin('foo/.bar', 'foo/.bar/baz'), isTrue);
+      expect(context.isWithin('foo/./bar', 'foo/.bar/baz'), isFalse);
+      expect(context.isWithin('foo/..bar', 'foo/..bar/baz'), isTrue);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/..'), isFalse);
+      expect(context.isWithin('foo/bar', 'foo/bar/baz/../qux'), isTrue);
+      expect(context.isWithin('http://example.org/', 'http://example.com/foo'),
+          isFalse);
+      expect(context.isWithin('http://example.org/', 'http://dartlang.org/foo'),
+          isFalse);
+    });
+
+    test('with root-relative paths', () {
+      expect(context.isWithin('/foo', 'http://dartlang.org/foo/bar'), isTrue);
+      expect(context.isWithin('http://dartlang.org/foo', '/foo/bar'), isTrue);
+      expect(context.isWithin('/root', 'foo/bar'), isTrue);
+      expect(context.isWithin('foo', '/root/path/foo/bar'), isTrue);
+      expect(context.isWithin('/foo', '/foo/bar'), isTrue);
+    });
+
     test('from a relative root', () {
       var r = new path.Context(style: path.Style.url, current: 'foo/bar');
       expect(r.isWithin('.', 'a/b/c'), isTrue);
diff --git a/packages/path/test/utils.dart b/packages/path/test/utils.dart
index 1730798..7d917a0 100644
--- a/packages/path/test/utils.dart
+++ b/packages/path/test/utils.dart
@@ -4,7 +4,7 @@
 
 library path.test.utils;
 
-import "package:unittest/unittest.dart";
+import "package:test/test.dart";
 import "package:path/path.dart" as path;
 
 /// A matcher for a closure that throws a [path.PathException].
diff --git a/packages/path/test/windows_test.dart b/packages/path/test/windows_test.dart
index 6942837..717043d 100644
--- a/packages/path/test/windows_test.dart
+++ b/packages/path/test/windows_test.dart
@@ -4,7 +4,7 @@
 
 library path.test.windows_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 import 'utils.dart';
@@ -13,7 +13,7 @@
   var context =
       new path.Context(style: path.Style.windows, current: r'C:\root\path');
 
-  group('separator', () {
+  test('separator', () {
     expect(context.separator, '\\');
   });
 
@@ -537,6 +537,30 @@
       expect(context.isWithin(r'baz', r'C:\root\path\bang\baz'), isFalse);
     });
 
+    test('complex cases', () {
+      expect(context.isWithin(r'foo\.\bar', r'foo\bar\baz'), isTrue);
+      expect(context.isWithin(r'foo\\bar', r'foo\bar\baz'), isTrue);
+      expect(context.isWithin(r'foo\qux\..\bar', r'foo\bar\baz'), isTrue);
+      expect(context.isWithin(r'foo\bar', r'foo\bar\baz\..\..'), isFalse);
+      expect(context.isWithin(r'foo\bar', r'foo\bar\\\'), isFalse);
+      expect(context.isWithin(r'foo\.bar', r'foo\.bar\baz'), isTrue);
+      expect(context.isWithin(r'foo\.\bar', r'foo\.bar\baz'), isFalse);
+      expect(context.isWithin(r'foo\..bar', r'foo\..bar\baz'), isTrue);
+      expect(context.isWithin(r'foo\bar', r'foo\bar\baz\..'), isFalse);
+      expect(context.isWithin(r'foo\bar', r'foo\bar\baz\..\qux'), isTrue);
+      expect(context.isWithin(r'C:\', 'C:/foo'), isTrue);
+      expect(context.isWithin(r'C:\', r'D:\foo'), isFalse);
+      expect(context.isWithin(r'C:\', r'\\foo\bar'), isFalse);
+    });
+
+    test('with root-relative paths', () {
+      expect(context.isWithin(r'\foo', r'C:\foo\bar'), isTrue);
+      expect(context.isWithin(r'C:\foo', r'\foo\bar'), isTrue);
+      expect(context.isWithin(r'\root', r'foo\bar'), isTrue);
+      expect(context.isWithin(r'foo', r'\root\path\foo\bar'), isTrue);
+      expect(context.isWithin(r'\foo', r'\foo\bar'), isTrue);
+    });
+
     test('from a relative root', () {
       var r = new path.Context(style: path.Style.windows, current: r'foo\bar');
       expect(r.isWithin('.', r'a\b\c'), isTrue);
diff --git a/packages/plugin/._AUTHORS b/packages/plugin/._AUTHORS
deleted file mode 100755
index 8fb8ff1..0000000
--- a/packages/plugin/._AUTHORS
+++ /dev/null
Binary files differ
diff --git a/packages/plugin/._CHANGELOG.md b/packages/plugin/._CHANGELOG.md
deleted file mode 100755
index 8fb8ff1..0000000
--- a/packages/plugin/._CHANGELOG.md
+++ /dev/null
Binary files differ
diff --git a/packages/plugin/._CONTRIBUTING.md b/packages/plugin/._CONTRIBUTING.md
deleted file mode 100755
index 8fb8ff1..0000000
--- a/packages/plugin/._CONTRIBUTING.md
+++ /dev/null
Binary files differ
diff --git a/packages/plugin/._LICENSE b/packages/plugin/._LICENSE
deleted file mode 100755
index 8fb8ff1..0000000
--- a/packages/plugin/._LICENSE
+++ /dev/null
Binary files differ
diff --git a/packages/plugin/._README.md b/packages/plugin/._README.md
deleted file mode 100755
index 8fb8ff1..0000000
--- a/packages/plugin/._README.md
+++ /dev/null
Binary files differ
diff --git a/packages/pool/CHANGELOG.md b/packages/pool/CHANGELOG.md
index 9f74d07..dc852aa 100644
--- a/packages/pool/CHANGELOG.md
+++ b/packages/pool/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.2.1
+
+* Internal changes only.
+
 ## 1.2.0
 
 * Add `Pool.close()`, which forbids new resource requests and releases all
diff --git a/packages/pool/lib/pool.dart b/packages/pool/lib/pool.dart
index 59b949e..ef38614 100644
--- a/packages/pool/lib/pool.dart
+++ b/packages/pool/lib/pool.dart
@@ -46,12 +46,14 @@
 
   /// The timeout timer.
   ///
-  /// If [_timeout] isn't null, this timer is set as soon as the resource limit
-  /// is reached and is reset every time an resource is released or a new
-  /// resource is requested. If it fires, that indicates that the caller became
-  /// deadlocked, likely due to files waiting for additional files to be read
-  /// before they could be closed.
-  Timer _timer;
+  /// This timer is canceled as long as the pool is below the resource limit.
+  /// It's reset once the resource limit is reached and again every time an
+  /// resource is released or a new resource is requested. If it fires, that
+  /// indicates that the caller became deadlocked, likely due to files waiting
+  /// for additional files to be read before they could be closed.
+  ///
+  /// This is `null` if this pool shouldn't time out.
+  RestartableTimer _timer;
 
   /// The amount of time to wait before timing out the pending resources.
   final Duration _timeout;
@@ -72,7 +74,13 @@
   /// all pending [request] futures will throw a [TimeoutException]. This is
   /// intended to avoid deadlocks.
   Pool(this._maxAllocatedResources, {Duration timeout})
-      : _timeout = timeout;
+      : _timeout = timeout {
+    if (timeout != null) {
+      // Start the timer canceled since we only want to start counting down once
+      // we've run out of available resources.
+      _timer = new RestartableTimer(timeout, _onTimeout)..cancel();
+    }
+  }
 
   /// Request a [PoolResource].
   ///
@@ -190,11 +198,12 @@
 
   /// A resource has been requested, allocated, or released.
   void _resetTimer() {
-    if (_timer != null) _timer.cancel();
-    if (_timeout == null || _requestedResources.isEmpty) {
-      _timer = null;
+    if (_timer == null) return;
+
+    if (_requestedResources.isEmpty) {
+      _timer.cancel();
     } else {
-      _timer = new Timer(_timeout, _onTimeout);
+      _timer.reset();
     }
   }
 
diff --git a/packages/pool/pubspec.yaml b/packages/pool/pubspec.yaml
index 0013e9e..9635620 100644
--- a/packages/pool/pubspec.yaml
+++ b/packages/pool/pubspec.yaml
@@ -1,10 +1,10 @@
 name: pool
-version: 1.2.0
+version: 1.2.1
 author: Dart Team <misc@dartlang.org>
 description: A class for managing a finite pool of resources.
 homepage: https://github.com/dart-lang/pool
 dependencies:
-  async: "^1.3.0"
+  async: "^1.4.0"
   stack_trace: ">=0.9.2 <2.0.0"
 environment:
   sdk: ">=1.9.0 <2.0.0"
diff --git a/packages/smoke/.packages b/packages/smoke/.packages
deleted file mode 100644
index 1d75e7a..0000000
--- a/packages/smoke/.packages
+++ /dev/null
@@ -1,30 +0,0 @@
-# Generate by pub on 2015-08-19 14:18:52.210.
-# This file contains a map from Dart package names to Dart package locations.
-# Dart tools, including the Dart VM and Dart analyzer, rely on the content.
-# AUTO GENERATED - DO NOT EDIT
-analyzer:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/analyzer-0.26.1/lib/
-args:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/args-0.13.2/lib/
-barback:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/barback-0.15.2+6/lib/
-charcode:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.0/lib/
-cli_util:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/cli_util-0.0.1+2/lib/
-code_transformers:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/code_transformers-0.2.9+1/lib/
-collection:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/collection-1.1.1/lib/
-csslib:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/csslib-0.12.1/lib/
-glob:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/glob-1.0.5/lib/
-html:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/html-0.12.1+2/lib/
-logging:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/logging-0.11.1+1/lib/
-package_config:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/package_config-0.1.1/lib/
-path:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/path-1.3.6/lib/
-plugin:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/plugin-0.1.0/lib/
-pool:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/pool-1.1.0/lib/
-smoke:lib/
-source_maps:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.1/lib/
-source_span:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/source_span-1.1.3/lib/
-stack_trace:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.4.1/lib/
-string_scanner:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/string_scanner-0.1.3+1/lib/
-unittest:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/unittest-0.11.6+1/lib/
-utf:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+2/lib/
-watcher:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7/lib/
-when:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/when-0.2.0/lib/
-which:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/which-0.1.3/lib/
-yaml:file:///usr/local/google/home/jakemac/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.3/lib/
diff --git a/packages/smoke/CHANGELOG.md b/packages/smoke/CHANGELOG.md
index 83bf042..ba83d54 100644
--- a/packages/smoke/CHANGELOG.md
+++ b/packages/smoke/CHANGELOG.md
@@ -1,3 +1,6 @@
+#### 0.3.6
+  * Update to analyzer '^0.27.0' and update to the test package.
+
 #### 0.3.5
   * Update to analyzer '<0.27.0'
 
diff --git a/packages/smoke/lib/codegen/recorder.dart b/packages/smoke/lib/codegen/recorder.dart
index 545455a..8a9ebf1 100644
--- a/packages/smoke/lib/codegen/recorder.dart
+++ b/packages/smoke/lib/codegen/recorder.dart
@@ -253,7 +253,7 @@
 
   /// Copy metadata associated with the declaration of [target].
   List<ConstExpression> _copyAnnotations(Element target) {
-    var node = target.node;
+    var node = target.computeNode();
     // [node] is the initialization expression, we walk up to get to the actual
     // member declaration where the metadata is attached to.
     while (node is! ClassMember) node = node.parent;
diff --git a/packages/smoke/lib/mirrors.dart b/packages/smoke/lib/mirrors.dart
index a84f081..ef018aa 100644
--- a/packages/smoke/lib/mirrors.dart
+++ b/packages/smoke/lib/mirrors.dart
@@ -222,7 +222,7 @@
       t = _objectType;
     }
     return t;
-  } on UnsupportedError catch (e) {
+  } on UnsupportedError catch (_) {
     // Note: dart2js throws UnsupportedError when the type is not reflectable.
     return _objectType;
   }
diff --git a/packages/smoke/lib/static.dart b/packages/smoke/lib/static.dart
index aad1542..2b5d065 100644
--- a/packages/smoke/lib/static.dart
+++ b/packages/smoke/lib/static.dart
@@ -145,7 +145,7 @@
     }
     try {
       return Function.apply(method, args);
-    } on NoSuchMethodError catch (e) {
+    } on NoSuchMethodError catch (_) {
       // TODO(sigmund): consider whether this should just be in a logger or if
       // we should wrap `e` as a new exception (what's the best way to let users
       // know about this tentativeError?)
diff --git a/packages/smoke/pubspec.yaml b/packages/smoke/pubspec.yaml
index 5e7cd83..58f0a80 100644
--- a/packages/smoke/pubspec.yaml
+++ b/packages/smoke/pubspec.yaml
@@ -1,5 +1,5 @@
 name: smoke
-version: 0.3.5
+version: 0.3.6
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 homepage: https://github.com/dart-lang/smoke
 description: >
@@ -9,7 +9,7 @@
 dependencies:
   barback: ">=0.9.0 <0.16.0"
   logging: ">=0.9.0 <0.12.0"
-  analyzer: ">=0.13.0 <0.27.0"
+  analyzer: "^0.27.0"
 # TODO(sigmund): once we have some easier way to do global app-level
 # transformers, we might want to remove this transformer here and only apply it
 # in apps that need it.
@@ -17,8 +17,8 @@
 - smoke/src/default_transformer:
     $include: lib/src/implementation.dart
 dev_dependencies:
-  unittest: ">=0.10.0 <0.12.0"
-  path: ">=1.0.0 <2.0.0"
-  code_transformers: ">=0.2.0 <0.3.0"
+  test: "^0.12.0"
+  path: "^1.0.0"
+  code_transformers: "^0.3.0"
 environment:
-  sdk: ">=1.3.0-dev.7.9 <2.0.0"
+  sdk: ">=1.12.0 <2.0.0"
diff --git a/packages/smoke/test/args_test.dart b/packages/smoke/test/args_test.dart
index 44c8079..4b5b089 100644
--- a/packages/smoke/test/args_test.dart
+++ b/packages/smoke/test/args_test.dart
@@ -7,7 +7,7 @@
 
 import 'package:smoke/smoke.dart'
     show minArgs, maxArgs, canAcceptNArgs, SUPPORTED_ARGS;
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 main() {
   var a = new A();
diff --git a/packages/smoke/test/codegen/common.dart b/packages/smoke/test/codegen/common.dart
index 7c80d6c..b595816 100644
--- a/packages/smoke/test/codegen/common.dart
+++ b/packages/smoke/test/codegen/common.dart
@@ -5,7 +5,7 @@
 library smoke.test.codegen.common;
 
 import 'package:smoke/codegen/generator.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 checkResults(SmokeCodeGenerator generator,
     {List<String> imports: const [], String topLevel: '', String initCall}) {
diff --git a/packages/smoke/test/codegen/end_to_end_test.dart b/packages/smoke/test/codegen/end_to_end_test.dart
index 62999a8..174d61a 100644
--- a/packages/smoke/test/codegen/end_to_end_test.dart
+++ b/packages/smoke/test/codegen/end_to_end_test.dart
@@ -15,13 +15,14 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:smoke/codegen/generator.dart';
 import 'package:smoke/codegen/recorder.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:path/path.dart' as path;
 
 import 'testing_resolver_utils.dart' show initAnalyzer;
 
-void main(List<String> args) {
-  final updateStaticTest = args.length > 0 && args[0] == '--update_static_test';
+void main([List<String> args]) {
+  final updateStaticTest =
+      args != null && args.length > 0 && args[0] == '--update_static_test';
 
   test('static_test is up to date', () {
     var scriptPath = path.fromUri(Platform.script);
@@ -136,7 +137,7 @@
       staticTestFile.writeAsStringSync(code);
       print('static_test.dart has been updated.');
     }
-  });
+  }, skip: 'https://github.com/dart-lang/smoke/issues/26');
 }
 
 String _createEntrypoint(SmokeCodeGenerator generator) {
diff --git a/packages/smoke/test/codegen/generator_test.dart b/packages/smoke/test/codegen/generator_test.dart
index 75860bb..3d3110f 100644
--- a/packages/smoke/test/codegen/generator_test.dart
+++ b/packages/smoke/test/codegen/generator_test.dart
@@ -5,7 +5,7 @@
 library smoke.test.codegen.generator_test;
 
 import 'package:smoke/codegen/generator.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 import 'common.dart' show checkResults;
 
diff --git a/packages/smoke/test/codegen/recorder_test.dart b/packages/smoke/test/codegen/recorder_test.dart
index cc6d54a..f4c777a 100644
--- a/packages/smoke/test/codegen/recorder_test.dart
+++ b/packages/smoke/test/codegen/recorder_test.dart
@@ -7,7 +7,7 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:smoke/codegen/generator.dart';
 import 'package:smoke/codegen/recorder.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 import 'common.dart' show checkResults;
 import 'testing_resolver_utils.dart' show initAnalyzer;
diff --git a/packages/smoke/test/codegen/testing_resolver_utils.dart b/packages/smoke/test/codegen/testing_resolver_utils.dart
index d824227..a2e62dc 100644
--- a/packages/smoke/test/codegen/testing_resolver_utils.dart
+++ b/packages/smoke/test/codegen/testing_resolver_utils.dart
@@ -24,6 +24,7 @@
 }
 
 LibraryProvider initAnalyzer(Map<String, String> contents) {
+  AnalysisEngine.instance.processRequiredPlugins();
   var analyzer = AnalysisEngine.instance.createAnalysisContext();
   var options = new AnalysisOptionsImpl()
     ..cacheSize = 256
diff --git a/packages/smoke/test/common.dart b/packages/smoke/test/common.dart
index 5400e74..6c511b2 100644
--- a/packages/smoke/test/common.dart
+++ b/packages/smoke/test/common.dart
@@ -7,7 +7,7 @@
 library smoke.test.common;
 
 import 'package:smoke/smoke.dart' as smoke;
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 main() {
   test('read value', () {
diff --git a/packages/smoke/test/common_utils_test.dart b/packages/smoke/test/common_utils_test.dart
index e62f1d1..e9818c9 100644
--- a/packages/smoke/test/common_utils_test.dart
+++ b/packages/smoke/test/common_utils_test.dart
@@ -5,7 +5,7 @@
 library smoke.test.common_utils;
 
 import 'package:smoke/src/common.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 
 main() {
   test('adjustList', () {
diff --git a/packages/smoke/test/mirrors_test.dart b/packages/smoke/test/mirrors_test.dart
index cac643a..ad93c87 100644
--- a/packages/smoke/test/mirrors_test.dart
+++ b/packages/smoke/test/mirrors_test.dart
@@ -5,7 +5,7 @@
 library smoke.test.mirrors_test;
 
 import 'package:smoke/mirrors.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'common.dart' as common show main;
 
 main() {
diff --git a/packages/smoke/test/mirrors_used_test.dart b/packages/smoke/test/mirrors_used_test.dart
index e2b6fc6..c2f542e 100644
--- a/packages/smoke/test/mirrors_used_test.dart
+++ b/packages/smoke/test/mirrors_used_test.dart
@@ -5,7 +5,7 @@
 library smoke.test.mirrors_test;
 
 import 'package:smoke/mirrors.dart';
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'common.dart' hide main;
 import 'common.dart' as common show main;
 
diff --git a/packages/smoke/test/static_in_pieces_test.dart b/packages/smoke/test/static_in_pieces_test.dart
index a18fbd2..b0682d7 100644
--- a/packages/smoke/test/static_in_pieces_test.dart
+++ b/packages/smoke/test/static_in_pieces_test.dart
@@ -6,7 +6,7 @@
 /// deferred imports.
 library smoke.test.static_in_pieces_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:smoke/smoke.dart' show Declaration, PROPERTY, METHOD;
 import 'package:smoke/static.dart' show useGeneratedCode, StaticConfiguration;
 import 'piece1.dart' as p1;
@@ -97,15 +97,18 @@
 main() {
   useGeneratedCode(configuration);
 
-  expect(configuration.getters[#j], isNull);
+  test('smoke', () async {
+    expect(configuration.getters[#j], isNull);
 
-  configuration.addAll(p1.configuration);
-  expect(configuration.getters[#j], isNotNull);
+    configuration.addAll(p1.configuration);
+    expect(configuration.getters[#j], isNotNull);
 
-  p2.loadLibrary().then((_) {
+    await p2.loadLibrary();
+
     expect(configuration.names[#i], isNull);
     configuration.addAll(p2.configuration);
     expect(configuration.names[#i], 'i');
-    common.main();
   });
+  
+  common.main();
 }
diff --git a/packages/smoke/test/static_test.dart b/packages/smoke/test/static_test.dart
index 6c485e4..9078225 100644
--- a/packages/smoke/test/static_test.dart
+++ b/packages/smoke/test/static_test.dart
@@ -5,7 +5,7 @@
 
 library smoke.test.static_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:smoke/smoke.dart' show Declaration, PROPERTY, METHOD;
 import 'package:smoke/static.dart' show useGeneratedCode, StaticConfiguration;
 import 'common.dart' as smoke_0;
diff --git a/packages/stack_trace/CHANGELOG.md b/packages/stack_trace/CHANGELOG.md
index dae0db6..624a934 100644
--- a/packages/stack_trace/CHANGELOG.md
+++ b/packages/stack_trace/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 1.5.0
+
+* `new Chain.parse()` now parses all the stack trace formats supported by `new
+  Trace.parse()`. Formats other than that emitted by `Chain.toString()` will
+  produce single-element chains.
+
+* `new Trace.parse()` now parses the output of `Chain.toString()`. It produces
+  the same result as `Chain.parse().toTrace()`.
+
 ## 1.4.2
 
 * Improve the display of `data:` URIs in stack traces.
diff --git a/packages/stack_trace/lib/src/chain.dart b/packages/stack_trace/lib/src/chain.dart
index acd17e9..2e07d4b 100644
--- a/packages/stack_trace/lib/src/chain.dart
+++ b/packages/stack_trace/lib/src/chain.dart
@@ -16,10 +16,6 @@
 /// A function that handles errors in the zone wrapped by [Chain.capture].
 typedef void ChainHandler(error, Chain chain);
 
-/// The line used in the string representation of stack chains to represent
-/// the gap between traces.
-const _gap = '===== asynchronous gap ===========================\n';
-
 /// A chain of stack traces.
 ///
 /// A stack chain is a collection of one or more stack traces that collectively
@@ -119,11 +115,15 @@
 
   /// Parses a string representation of a stack chain.
   ///
-  /// Specifically, this parses the output of [Chain.toString].
+  /// If [chain] is the output of a call to [Chain.toString], it will be parsed
+  /// as a full stack chain. Otherwise, it will be parsed as in [Trace.parse]
+  /// and returned as a single-trace chain.
   factory Chain.parse(String chain) {
     if (chain.isEmpty) return new Chain([]);
+    if (!chain.contains(chainGap)) return new Chain([new Trace.parse(chain)]);
+
     return new Chain(
-        chain.split(_gap).map((trace) => new Trace.parseFriendly(trace)));
+        chain.split(chainGap).map((trace) => new Trace.parseFriendly(trace)));
   }
 
   /// Returns a new [Chain] comprised of [traces].
@@ -191,6 +191,6 @@
       return trace.frames.map((frame) {
         return '${padRight(frame.location, longest)}  ${frame.member}\n';
       }).join();
-    }).join(_gap);
+    }).join(chainGap);
   }
 }
diff --git a/packages/stack_trace/lib/src/trace.dart b/packages/stack_trace/lib/src/trace.dart
index f615cd2..7f2c662 100644
--- a/packages/stack_trace/lib/src/trace.dart
+++ b/packages/stack_trace/lib/src/trace.dart
@@ -111,7 +111,8 @@
   /// Parses a string representation of a stack trace.
   ///
   /// [trace] should be formatted in the same way as a Dart VM or browser stack
-  /// trace.
+  /// trace. If it's formatted as a stack chain, this will return the equivalent
+  /// of [Chain.toTrace].
   factory Trace.parse(String trace) {
     try {
       if (trace.isEmpty) return new Trace(<Frame>[]);
@@ -120,6 +121,7 @@
       if (trace.contains(_firefoxSafariTrace)) {
         return new Trace.parseFirefox(trace);
       }
+      if (trace.contains(chainGap)) return new Chain.parse(trace).toTrace();
       if (trace.contains(_friendlyTrace)) {
         return new Trace.parseFriendly(trace);
       }
diff --git a/packages/stack_trace/lib/src/utils.dart b/packages/stack_trace/lib/src/utils.dart
index 62a2820..1d09443 100644
--- a/packages/stack_trace/lib/src/utils.dart
+++ b/packages/stack_trace/lib/src/utils.dart
@@ -4,6 +4,10 @@
 
 library stack_trace.src.utils;
 
+/// The line used in the string representation of stack chains to represent
+/// the gap between traces.
+const chainGap = '===== asynchronous gap ===========================\n';
+
 /// Returns [string] with enough spaces added to the end to make it [length]
 /// characters long.
 String padRight(String string, int length) {
diff --git a/packages/stack_trace/pubspec.yaml b/packages/stack_trace/pubspec.yaml
index 5c8b720..932f648 100644
--- a/packages/stack_trace/pubspec.yaml
+++ b/packages/stack_trace/pubspec.yaml
@@ -7,7 +7,7 @@
 #
 # When the major version is upgraded, you *must* update that version constraint
 # in pub to stay in sync with this.
-version: 1.4.2
+version: 1.5.0
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://github.com/dart-lang/stack_trace
 description: >
diff --git a/packages/usage/.gitignore b/packages/usage/.gitignore
index 2a3df19..f8192d2 100644
--- a/packages/usage/.gitignore
+++ b/packages/usage/.gitignore
@@ -1,4 +1,6 @@
 build/
+doc/api/
+.packages
 packages
 .buildlog
 pubspec.lock
diff --git a/packages/usage/.travis.yml b/packages/usage/.travis.yml
index d1eaab0..75b3aac 100644
--- a/packages/usage/.travis.yml
+++ b/packages/usage/.travis.yml
@@ -1,14 +1,12 @@
 language: dart
-before_install:
-  - "export CHROME_ARGS=--no-sandbox"
-  - "export DISPLAY=:99.0"
-  - "sh -e /etc/init.d/xvfb start"
-script: ./tool/travis.sh
-
-# Use container based builds; enable caching.
+dart:
+  - stable
+  - dev
 sudo: false
-cache:
-  apt: true
-  directories:
-  - .pub
-  - .pub-cache
+
+# 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/packages/usage/changelog.md b/packages/usage/changelog.md
index 6d49030..b20ef31 100644
--- a/packages/usage/changelog.md
+++ b/packages/usage/changelog.md
@@ -1,5 +1,9 @@
 # Changelog
 
+## 1.0.1
+- make strong mode compliant
+- update some dev package dependencies
+
 ## 1.0.0
 - Rev'd to 1.0.0!
 - No other changes from the `0.0.6` release
diff --git a/packages/usage/lib/src/usage_impl.dart b/packages/usage/lib/src/usage_impl.dart
index fc2c8a7..307b6ba 100644
--- a/packages/usage/lib/src/usage_impl.dart
+++ b/packages/usage/lib/src/usage_impl.dart
@@ -91,14 +91,14 @@
   bool get hasSetOptIn => properties['optIn'] != null;
 
   Future sendScreenView(String viewName) {
-    Map args = {'cd': viewName};
+    Map<String, dynamic> args = {'cd': viewName};
     return _sendPayload('screenview', args);
   }
 
   Future sendEvent(String category, String action, {String label, int value}) {
     if (!optIn) return new Future.value();
 
-    Map args = {'ec': category, 'ea': action};
+    Map<String, dynamic> args = {'ec': category, 'ea': action};
     if (label != null) args['el'] = label;
     if (value != null) args['ev'] = value;
     return _sendPayload('event', args);
@@ -107,7 +107,7 @@
   Future sendSocial(String network, String action, String target) {
     if (!optIn) return new Future.value();
 
-    Map args = {'sn': network, 'sa': action, 'st': target};
+    Map<String, dynamic> args = {'sn': network, 'sa': action, 'st': target};
     return _sendPayload('social', args);
   }
 
@@ -115,7 +115,7 @@
         String label}) {
     if (!optIn) return new Future.value();
 
-    Map args = {'utv': variableName, 'utt': time};
+    Map<String, dynamic> args = {'utv': variableName, 'utt': time};
     if (label != null) args['utl'] = label;
     if (category != null) args['utc'] = category;
     return _sendPayload('timing', args);
@@ -140,7 +140,7 @@
       description = description.substring(0, _MAX_EXCEPTION_LENGTH);
     }
 
-    Map args = {'exd': description};
+    Map<String, dynamic> args = {'exd': description};
     if (fatal != null && fatal) args['exf'] = '1';
     return _sendPayload('exception', args);
   }
@@ -176,7 +176,7 @@
 
   // Valid values for [hitType] are: 'pageview', 'screenview', 'event',
   // 'transaction', 'item', 'social', 'exception', and 'timing'.
-  Future _sendPayload(String hitType, Map args) {
+  Future _sendPayload(String hitType, Map<String, dynamic> args) {
     if (_bucket.removeDrop()) {
       _initClientId();
 
@@ -228,5 +228,5 @@
  * send the information should be silent.
  */
 abstract class PostHandler {
-  Future sendPost(String url, Map<String, String> parameters);
+  Future sendPost(String url, Map<String, dynamic> parameters);
 }
diff --git a/packages/usage/lib/src/usage_impl_html.dart b/packages/usage/lib/src/usage_impl_html.dart
index fafd77a..e3f6496 100644
--- a/packages/usage/lib/src/usage_impl_html.dart
+++ b/packages/usage/lib/src/usage_impl_html.dart
@@ -15,7 +15,7 @@
 
   HtmlPostHandler({Function this.mockRequestor});
 
-  Future sendPost(String url, Map<String, String> parameters) {
+  Future sendPost(String url, Map<String, dynamic> parameters) {
     int viewportWidth = document.documentElement.clientWidth;
     int viewportHeight = document.documentElement.clientHeight;
 
diff --git a/packages/usage/lib/src/usage_impl_io.dart b/packages/usage/lib/src/usage_impl_io.dart
index 66fe0cb..d59793e 100644
--- a/packages/usage/lib/src/usage_impl_io.dart
+++ b/packages/usage/lib/src/usage_impl_io.dart
@@ -39,7 +39,7 @@
 
   IOPostHandler({HttpClient this.mockClient}) : _userAgent = _createUserAgent();
 
-  Future sendPost(String url, Map<String, String> parameters) {
+  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()}';
diff --git a/packages/usage/pubspec.yaml b/packages/usage/pubspec.yaml
index 28905c5..4d6ca7b 100644
--- a/packages/usage/pubspec.yaml
+++ b/packages/usage/pubspec.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: usage
-version: 1.0.0+1
+version: 1.0.1
 description: A Google Analytics wrapper for both command-line and web apps.
 homepage: https://github.com/dart-lang/usage
 author: Dart Team <misc@dartlang.org>
@@ -12,6 +12,6 @@
   sdk: '>=1.0.0 <2.0.0'
 
 dev_dependencies:
-  browser: any
-  grinder: '>=0.6.6+3 <0.7.0'
-  unittest: any
+  browser: ^0.10.0
+  grinder: ^0.7.0
+  test: ^0.12.0
diff --git a/packages/usage/test/hit_types_test.dart b/packages/usage/test/hit_types_test.dart
index 6cfa321..4bfb608 100644
--- a/packages/usage/test/hit_types_test.dart
+++ b/packages/usage/test/hit_types_test.dart
@@ -6,11 +6,13 @@
 
 import 'dart:async';
 
+import 'package:test/test.dart';
 import 'package:usage/usage.dart';
-import 'package:unittest/unittest.dart';
 
 import 'src/common.dart';
 
+main() => defineTests();
+
 void defineTests() {
   group('screenView', () {
     test('simple', () {
@@ -81,8 +83,6 @@
       AnalyticsTimer timer =
           mock.startTimer('compile', category: 'Build', label: 'Compile');
 
-      int time;
-
       return new Future.delayed(new Duration(milliseconds: 20), () {
         return timer.finish().then((_) {
           expect(mock.mockPostHandler.sentValues, isNot(isEmpty));
diff --git a/packages/usage/test/src/common.dart b/packages/usage/test/src/common.dart
index 44c9960..238ce6d 100644
--- a/packages/usage/test/src/common.dart
+++ b/packages/usage/test/src/common.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:usage/src/usage_impl.dart';
 
 AnalyticsImplMock createMock({bool setOptIn: true}) =>
@@ -42,9 +42,9 @@
 }
 
 class MockPostHandler extends PostHandler {
-  List<Map> sentValues = [];
+  List<Map<String, dynamic>> sentValues = [];
 
-  Future sendPost(String url, Map<String, String> parameters) {
+  Future sendPost(String url, Map<String, dynamic> parameters) {
     sentValues.add(parameters);
 
     return new Future.value();
diff --git a/packages/usage/test/usage_impl_io_test.dart b/packages/usage/test/usage_impl_io_test.dart
index a0eec18..e41f241 100644
--- a/packages/usage/test/usage_impl_io_test.dart
+++ b/packages/usage/test/usage_impl_io_test.dart
@@ -7,15 +7,17 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:usage/src/usage_impl_io.dart';
 
+main() => defineTests();
+
 void defineTests() {
   group('IOPostHandler', () {
     test('sendPost', () {
       var httpClient = new MockHttpClient();
       IOPostHandler postHandler = new IOPostHandler(mockClient: httpClient);
-      Map args = {'utv': 'varName', 'utt': 123};
+      Map<String, dynamic> args = {'utv': 'varName', 'utt': 123};
       return postHandler.sendPost('http://www.google.com', args).then((_) {
         expect(httpClient.sendCount, 1);
       });
diff --git a/packages/usage/test/usage_impl_test.dart b/packages/usage/test/usage_impl_test.dart
index 8601cee..b8c0f05 100644
--- a/packages/usage/test/usage_impl_test.dart
+++ b/packages/usage/test/usage_impl_test.dart
@@ -4,11 +4,13 @@
 
 library usage.impl_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:usage/src/usage_impl.dart';
 
 import 'src/common.dart';
 
+main() => defineTests();
+
 void defineTests() {
   group('ThrottlingBucket', () {
     test('can send', () {
@@ -64,7 +66,7 @@
 
   group('postEncode', () {
     test('simple', () {
-      Map map = {'foo': 'bar', 'baz': 'qux norf'};
+      Map<String, dynamic> map = {'foo': 'bar', 'baz': 'qux norf'};
       expect(postEncode(map), 'foo=bar&baz=qux%20norf');
     });
   });
diff --git a/packages/usage/test/usage_test.dart b/packages/usage/test/usage_test.dart
index 6184f09..bdbd6f1 100644
--- a/packages/usage/test/usage_test.dart
+++ b/packages/usage/test/usage_test.dart
@@ -4,9 +4,11 @@
 
 library usage.usage_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:usage/usage.dart';
 
+main() => defineTests();
+
 void defineTests() {
   group('AnalyticsMock', () {
     test('simple', () {
diff --git a/packages/usage/test/uuid_test.dart b/packages/usage/test/uuid_test.dart
index cdde2b6..335d878 100644
--- a/packages/usage/test/uuid_test.dart
+++ b/packages/usage/test/uuid_test.dart
@@ -4,9 +4,11 @@
 
 library usage.uuid_test;
 
-import 'package:unittest/unittest.dart';
+import 'package:test/test.dart';
 import 'package:usage/src/uuid.dart';
 
+main() => defineTests();
+
 void defineTests() {
   group('uuid', () {
     // xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
diff --git a/packages/usage/test/web_test.dart b/packages/usage/test/web_test.dart
index 0b79e89..5a9cd98 100644
--- a/packages/usage/test/web_test.dart
+++ b/packages/usage/test/web_test.dart
@@ -2,23 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+@TestOn("browser")
 library usage.web_test;
 
 import 'dart:async';
 
-import 'package:grinder/src/webtest.dart';
+import 'package:test/test.dart';
 import 'package:usage/src/usage_impl_html.dart';
-import 'package:unittest/unittest.dart';
 
 import 'hit_types_test.dart' as hit_types_test;
-import 'usage_test.dart' as usage_test;
 import 'usage_impl_test.dart' as usage_impl_test;
+import 'usage_test.dart' as usage_test;
 import 'uuid_test.dart' as uuid_test;
 
 void main() {
-  // Set up the test environment.
-  WebTestConfiguration.setupTestEnvironment();
-
   // Define the tests.
   hit_types_test.defineTests();
   usage_test.defineTests();
diff --git a/packages/usage/tool/grind.dart b/packages/usage/tool/grind.dart
index da63dc2..f1d8121 100644
--- a/packages/usage/tool/grind.dart
+++ b/packages/usage/tool/grind.dart
@@ -8,40 +8,35 @@
 
 import 'package:grinder/grinder.dart';
 
-final Directory BUILD_DIR = new Directory('build');
-final Directory BUILD_TEST_DIR = new Directory('build/test');
+final Directory _buildExampleDir = new Directory('build/example');
 
-void main(List<String> args) {
-  task('init', init);
-  task('build', build, ['init']);
-  task('clean', clean);
+main(List<String> args) => grind(args);
 
-  startGrinder(args);
-}
-
-/// Do any necessary build set up.
-void init(GrinderContext context) {
+@Task('Do any necessary build set up')
+void init() {
   // Verify we're running in the project root.
   if (!getDir('lib').existsSync() || !getFile('pubspec.yaml').existsSync()) {
     context.fail('This script must be run from the project root.');
   }
 
-  BUILD_TEST_DIR.createSync(recursive: true);
+  _buildExampleDir.createSync(recursive: true);
 }
 
-void build(GrinderContext context) {
+@Task()
+@Depends(init)
+void build() {
   // Compile `test/web_test.dart` to the `build/test` dir; measure its size.
-  File srcFile = new File('test/web_test.dart');
-  Dart2js.compile(context, srcFile, outDir: BUILD_TEST_DIR, minify: true);
-  File outFile = joinFile(BUILD_TEST_DIR, ['web_test.dart.js']);
+  File srcFile = new File('example/example.dart');
+  Dart2js.compile(srcFile, outDir: _buildExampleDir, minify: true);
+  File outFile = joinFile(_buildExampleDir, ['example.dart.js']);
 
   context.log('${outFile.path} compiled to ${_printSize(outFile)}');
 }
 
-/// Delete all generated artifacts.
-void clean(GrinderContext context) {
+@Task('Delete all generated artifacts')
+void clean() {
   // Delete the build/ dir.
-  deleteEntity(BUILD_DIR, context);
+  delete(buildDir);
 }
 
 String _printSize(File file) => '${(file.lengthSync() + 1023) ~/ 1024}k';
diff --git a/packages/usage/tool/travis.sh b/packages/usage/tool/travis.sh
index 699e808..5b6e2dd 100755
--- a/packages/usage/tool/travis.sh
+++ b/packages/usage/tool/travis.sh
@@ -15,11 +15,15 @@
   test/all.dart
 
 # Run the tests.
-dart test/all.dart
+dart -c test/all.dart
 
 # Run the UI/web tests as well.
-pub build test
-pub run grinder:test build/test/web.html
+#pub build test
+#pub run grinder:test build/test/web.html
+
+# Verify against DDC.
+pub global activate dev_compiler
+pub global run dev_compiler lib/usage_html.dart
 
 # Measure the size of the compiled JS, for the dart:html version of the library.
 dart tool/grind.dart build
diff --git a/pubspec.yaml b/pubspec.yaml
index 85abc62..e964459 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,15 +7,17 @@
     inline_stylesheets:
       lib/src/elements/css/shared.css: false
       packages/charted/charts/themes/quantum_theme.css: false
+    $exclude: [web/third_party/*.html, web/timeline.html]
 - $dart2js:
     $include: "**/*.polymer.bootstrap.dart"
     suppressWarnings: false
     commandLineOptions: [--show-package-warnings]
 dependencies:
   args: any
-  charted: ^0.2.9
+  charted: ^0.3.0
   polymer: ^0.16.3
   unittest: < 0.12.0
   usage: any
 dependency_overrides:
-  analyzer: ^0.26.1
+  analyzer: '>=0.26.1 <0.26.1+15'
+  dart_style: <0.2.2