Version 1.8.0-dev.2.0

svn merge -r 41254:41388 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@41389 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/compiler/implementation/lib/web.dart b/lib/compiler/implementation/lib/web.dart
new file mode 100644
index 0000000..a75db7b
--- /dev/null
+++ b/lib/compiler/implementation/lib/web.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#library("web");
+
+String htmlEscape(String text) {
+  throw "Unimplemented: web::htmlEscape(String).";
+}
diff --git a/lib/compiler/implementation/lib/web.dartp b/lib/compiler/implementation/lib/web.dartp
new file mode 100644
index 0000000..c3ba2ad
--- /dev/null
+++ b/lib/compiler/implementation/lib/web.dartp
@@ -0,0 +1,13 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Patch file for dart:web
+
+/*patch*/ String htmlEscape(String text) {
+  return text.replaceAll("&", "&")
+             .replaceAll("<", "&lt;")
+             .replaceAll(">", "&gt;")
+             .replaceAll('"', "&quot;")
+             .replaceAll("'", "&apos;");  // Different from original.
+}
diff --git a/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate b/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate
new file mode 100644
index 0000000..8fe27e5
--- /dev/null
+++ b/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate
@@ -0,0 +1,7 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _Elements {
+
+$!FACTORY_METHODS}
diff --git a/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate b/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate
new file mode 100644
index 0000000..1b4a00d
--- /dev/null
+++ b/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate
@@ -0,0 +1,106 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _EventsImpl implements Events {
+  // TODO(podivilov): add type.
+  final _ptr;
+
+  final Map<String, EventListenerList> _listenerMap;
+
+  _EventsImpl(this._ptr) : _listenerMap = <EventListenerList>{};
+
+  EventListenerList operator [](String type) {
+    return _listenerMap.putIfAbsent(type,
+      () => new _EventListenerListImpl(_ptr, type));
+  }
+}
+
+class _EventListenerWrapper {
+  final EventListener raw;
+  final Function wrapped;
+  final bool useCapture;
+  _EventListenerWrapper(this.raw, this.wrapped, this.useCapture);
+}
+
+class _EventListenerListImpl implements EventListenerList {
+  // TODO(podivilov): add type.
+  final _ptr;
+  final String _type;
+  List<_EventListenerWrapper> _wrappers;
+
+  _EventListenerListImpl(this._ptr, this._type) :
+    // TODO(jacobr): switch to <_EventListenerWrapper>[] when the VM allow it.
+    _wrappers = new List<_EventListenerWrapper>();
+
+  EventListenerList add(EventListener listener, [bool useCapture = false]) {
+    _add(listener, useCapture);
+    return this;
+  }
+
+  EventListenerList remove(EventListener listener, [bool useCapture = false]) {
+    _remove(listener, useCapture);
+    return this;
+  }
+
+  bool dispatch(Event evt) {
+    // TODO(jacobr): what is the correct behavior here. We could alternately
+    // force the event to have the expected type.
+    assert(evt.type == _type);
+    return _ptr.$dom_dispatchEvent(evt);
+  }
+
+  void _add(EventListener listener, bool useCapture) {
+    _ptr.$dom_addEventListener(_type,
+                          _findOrAddWrapper(listener, useCapture),
+                          useCapture);
+  }
+
+  void _remove(EventListener listener, bool useCapture) {
+    Function wrapper = _removeWrapper(listener, useCapture);
+    if (wrapper !== null) {
+      _ptr.$dom_removeEventListener(_type, wrapper, useCapture);
+    }
+  }
+
+  Function _removeWrapper(EventListener listener, bool useCapture) {
+    if (_wrappers === null) {
+      return null;
+    }
+    for (int i = 0; i < _wrappers.length; i++) {
+      _EventListenerWrapper wrapper = _wrappers[i];
+      if (wrapper.raw === listener && wrapper.useCapture == useCapture) {
+        // Order doesn't matter so we swap with the last element instead of
+        // performing a more expensive remove from the middle of the list.
+        if (i + 1 != _wrappers.length) {
+          _wrappers[i] = _wrappers.removeLast();
+        } else {
+          _wrappers.removeLast();
+        }
+        return wrapper.wrapped;
+      }
+    }
+    return null;
+  }
+
+  Function _findOrAddWrapper(EventListener listener, bool useCapture) {
+    if (_wrappers === null) {
+      _wrappers = <_EventListenerWrapper>[];
+    } else {
+      for (_EventListenerWrapper wrapper in _wrappers) {
+        if (wrapper.raw === listener && wrapper.useCapture == useCapture) {
+          return wrapper.wrapped;
+        }
+      }
+    }
+    final wrapped = (e) { listener(e); };
+    _wrappers.add(new _EventListenerWrapper(listener, wrapped, useCapture));
+    return wrapped;
+  }
+}
+
+class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+/*
+$!MEMBERS
+*/
+}
diff --git a/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate b/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate
new file mode 100644
index 0000000..8fe27e5
--- /dev/null
+++ b/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate
@@ -0,0 +1,7 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _Elements {
+
+$!FACTORY_METHODS}
diff --git a/lib/dom/templates/html/frog/impl_EventTarget.darttemplate b/lib/dom/templates/html/frog/impl_EventTarget.darttemplate
new file mode 100644
index 0000000..893f3d2
--- /dev/null
+++ b/lib/dom/templates/html/frog/impl_EventTarget.darttemplate
@@ -0,0 +1,61 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _EventsImpl implements Events {
+  /* Raw event target. */
+  // TODO(jacobr): it would be nice if we could specify this as
+  // _EventTargetImpl or EventTarget
+  final Dynamic _ptr;
+
+  _EventsImpl(this._ptr);
+
+  _EventListenerListImpl operator [](String type) {
+    return new _EventListenerListImpl(_ptr, type);
+  }
+}
+
+class _EventListenerListImpl implements EventListenerList {
+  
+  // TODO(jacobr): make this _EventTargetImpl
+  final Dynamic _ptr;
+  final String _type;
+
+  _EventListenerListImpl(this._ptr, this._type);
+
+  // TODO(jacobr): implement equals.
+
+  _EventListenerListImpl add(EventListener listener,
+      [bool useCapture = false]) {
+    _add(listener, useCapture);
+    return this;
+  }
+
+  _EventListenerListImpl remove(EventListener listener,
+      [bool useCapture = false]) {
+    _remove(listener, useCapture);
+    return this;
+  }
+
+  bool dispatch(Event evt) {
+    // TODO(jacobr): what is the correct behavior here. We could alternately
+    // force the event to have the expected type.
+    assert(evt.type == _type);
+    return _ptr.$dom_dispatchEvent(evt);
+  }
+
+  void _add(EventListener listener, bool useCapture) {
+    _ptr.$dom_addEventListener(_type, listener, useCapture);
+  }
+
+  void _remove(EventListener listener, bool useCapture) {
+    _ptr.$dom_removeEventListener(_type, listener, useCapture);
+  }
+}
+
+
+class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+
+  Events get on() => new _EventsImpl(this);
+$!MEMBERS
+}
diff --git a/pkg/analysis_server/lib/src/computers.dart b/pkg/analysis_server/lib/src/computers.dart
new file mode 100644
index 0000000..6b954dc
--- /dev/null
+++ b/pkg/analysis_server/lib/src/computers.dart
@@ -0,0 +1,712 @@
+// 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.
+
+library computers;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+
+/**
+ * A computer for [HighlightRegion]s in a Dart [CompilationUnit].
+ */
+class DartUnitHighlightsComputer {
+  final CompilationUnit _unit;
+
+  final List<Map<String, Object>> _regions = <Map<String, Object>>[];
+
+  DartUnitHighlightsComputer(this._unit);
+
+  /**
+   * Returns the computed highlight regions, not `null`.
+   */
+  List<Map<String, Object>> compute() {
+    _unit.accept(new _DartUnitHighlightsComputerVisitor(this));
+    return _regions;
+  }
+
+  void _addIdentifierRegion(SimpleIdentifier node) {
+    if (_addIdentifierRegion_keyword(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_class(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_constructor(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_dynamicType(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_getterSetterDeclaration(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_field(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_function(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_functionTypeAlias(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_importPrefix(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_localVariable(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_method(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_parameter(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_topLevelVariable(node)) {
+      return;
+    }
+    if (_addIdentifierRegion_typeParameter(node)) {
+      return;
+    }
+    _addRegion_node(node, HighlightType.IDENTIFIER_DEFAULT);
+  }
+
+  void _addIdentifierRegion_annotation(Annotation node) {
+    ArgumentList arguments = node.arguments;
+    if (arguments == null) {
+      _addRegion_node(node, HighlightType.ANNOTATION);
+    } else {
+      _addRegion_nodeStart_tokenEnd(node, arguments.beginToken, HighlightType.ANNOTATION);
+      _addRegion_token(arguments.endToken, HighlightType.ANNOTATION);
+    }
+  }
+
+  bool _addIdentifierRegion_class(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! ClassElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.CLASS);
+  }
+
+  bool _addIdentifierRegion_constructor(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! ConstructorElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.CONSTRUCTOR);
+  }
+
+  bool _addIdentifierRegion_dynamicType(SimpleIdentifier node) {
+    // should be variable
+    Element element = node.staticElement;
+    if (element is! VariableElement) {
+      return false;
+    }
+    // has propagated type
+    if (node.propagatedType != null) {
+      return false;
+    }
+    // has dynamic static type
+    DartType staticType = node.staticType;
+    if (staticType == null || !staticType.isDynamic) {
+      return false;
+    }
+    // OK
+    return _addRegion_node(node, HighlightType.DYNAMIC_TYPE);
+  }
+
+  bool _addIdentifierRegion_field(SimpleIdentifier node) {
+    Element element = node.bestElement;
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
+    if (element is FieldElement) {
+      if ((element as FieldElement).isStatic) {
+        return _addRegion_node(node, HighlightType.FIELD_STATIC);
+      } else {
+        return _addRegion_node(node, HighlightType.FIELD);
+      }
+    }
+    if (element is PropertyAccessorElement) {
+      if ((element as PropertyAccessorElement).isStatic) {
+        return _addRegion_node(node, HighlightType.FIELD_STATIC);
+      } else {
+        return _addRegion_node(node, HighlightType.FIELD);
+      }
+    }
+    return false;
+  }
+
+  bool _addIdentifierRegion_function(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! FunctionElement) {
+      return false;
+    }
+    HighlightType type;
+    if (node.inDeclarationContext()) {
+      type = HighlightType.FUNCTION_DECLARATION;
+    } else {
+      type = HighlightType.FUNCTION;
+    }
+    return _addRegion_node(node, type);
+  }
+
+  bool _addIdentifierRegion_functionTypeAlias(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! FunctionTypeAliasElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.FUNCTION_TYPE_ALIAS);
+  }
+
+  bool _addIdentifierRegion_getterSetterDeclaration(SimpleIdentifier node) {
+    // should be declaration
+    AstNode parent = node.parent;
+    if (!(parent is MethodDeclaration || parent is FunctionDeclaration)) {
+      return false;
+    }
+    // should be property accessor
+    Element element = node.staticElement;
+    if (element is! PropertyAccessorElement) {
+      return false;
+    }
+    // getter or setter
+    PropertyAccessorElement propertyAccessorElement = element as PropertyAccessorElement;
+    if (propertyAccessorElement.isGetter) {
+      return _addRegion_node(node, HighlightType.GETTER_DECLARATION);
+    } else {
+      return _addRegion_node(node, HighlightType.SETTER_DECLARATION);
+    }
+  }
+
+  bool _addIdentifierRegion_importPrefix(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! PrefixElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.IMPORT_PREFIX);
+  }
+
+  bool _addIdentifierRegion_keyword(SimpleIdentifier node) {
+    String name = node.name;
+    if (name == "void") {
+      return _addRegion_node(node, HighlightType.KEYWORD);
+    }
+    return false;
+  }
+
+  bool _addIdentifierRegion_localVariable(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! LocalVariableElement) {
+      return false;
+    }
+    // OK
+    HighlightType type;
+    if (node.inDeclarationContext()) {
+      type = HighlightType.LOCAL_VARIABLE_DECLARATION;
+    } else {
+      type = HighlightType.LOCAL_VARIABLE;
+    }
+    return _addRegion_node(node, type);
+  }
+
+  bool _addIdentifierRegion_method(SimpleIdentifier node) {
+    Element element = node.bestElement;
+    if (element is! MethodElement) {
+      return false;
+    }
+    MethodElement methodElement = element as MethodElement;
+    bool isStatic = methodElement.isStatic;
+    // OK
+    HighlightType type;
+    if (node.inDeclarationContext()) {
+      if (isStatic) {
+        type = HighlightType.METHOD_DECLARATION_STATIC;
+      } else {
+        type = HighlightType.METHOD_DECLARATION;
+      }
+    } else {
+      if (isStatic) {
+        type = HighlightType.METHOD_STATIC;
+      } else {
+        type = HighlightType.METHOD;
+      }
+    }
+    return _addRegion_node(node, type);
+  }
+
+  bool _addIdentifierRegion_parameter(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! ParameterElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.PARAMETER);
+  }
+
+  bool _addIdentifierRegion_topLevelVariable(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! TopLevelVariableElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.TOP_LEVEL_VARIABLE);
+  }
+
+  bool _addIdentifierRegion_typeParameter(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    if (element is! TypeParameterElement) {
+      return false;
+    }
+    return _addRegion_node(node, HighlightType.TYPE_PARAMETER);
+  }
+
+  void _addRegion(int offset, int length, HighlightType type) {
+    _regions.add({'offset': offset, 'length': length, 'type': type.name});
+  }
+
+  bool _addRegion_node(AstNode node, HighlightType type) {
+    int offset = node.offset;
+    int length = node.length;
+    _addRegion(offset, length, type);
+    return true;
+  }
+
+  void _addRegion_nodeStart_tokenEnd(AstNode a, Token b, HighlightType type) {
+    int offset = a.offset;
+    int end = b.end;
+    _addRegion(offset, end - offset, type);
+  }
+
+  void _addRegion_token(Token token, HighlightType type) {
+    if (token != null) {
+      int offset = token.offset;
+      int length = token.length;
+      _addRegion(offset, length, type);
+    }
+  }
+
+  void _addRegion_tokenStart_tokenEnd(Token a, Token b, HighlightType type) {
+    int offset = a.offset;
+    int end = b.end;
+    _addRegion(offset, end - offset, type);
+  }
+}
+
+
+/**
+ * An AST visitor for [DartUnitHighlightsComputer].
+ */
+class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor<Object> {
+  final DartUnitHighlightsComputer computer;
+
+  _DartUnitHighlightsComputerVisitor(this.computer);
+
+  @override
+  Object visitAnnotation(Annotation node) {
+    computer._addIdentifierRegion_annotation(node);
+    return super.visitAnnotation(node);
+  }
+
+  @override
+  Object visitAsExpression(AsExpression node) {
+    computer._addRegion_token(node.asOperator, HighlightType.BUILT_IN);
+    return super.visitAsExpression(node);
+  }
+
+  @override
+  Object visitBooleanLiteral(BooleanLiteral node) {
+    computer._addRegion_node(node, HighlightType.LITERAL_BOOLEAN);
+    return super.visitBooleanLiteral(node);
+  }
+
+  @override
+  Object visitCatchClause(CatchClause node) {
+    computer._addRegion_token(node.onKeyword, HighlightType.BUILT_IN);
+    return super.visitCatchClause(node);
+  }
+
+  @override
+  Object visitClassDeclaration(ClassDeclaration node) {
+    computer._addRegion_token(node.abstractKeyword, HighlightType.BUILT_IN);
+    return super.visitClassDeclaration(node);
+  }
+
+  @override
+  Object visitConstructorDeclaration(ConstructorDeclaration node) {
+    computer._addRegion_token(node.externalKeyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.factoryKeyword, HighlightType.BUILT_IN);
+    return super.visitConstructorDeclaration(node);
+  }
+
+  @override
+  Object visitDoubleLiteral(DoubleLiteral node) {
+    computer._addRegion_node(node, HighlightType.LITERAL_DOUBLE);
+    return super.visitDoubleLiteral(node);
+  }
+
+  @override
+  Object visitExportDirective(ExportDirective node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitExportDirective(node);
+  }
+
+  @override
+  Object visitFieldDeclaration(FieldDeclaration node) {
+    computer._addRegion_token(node.staticKeyword, HighlightType.BUILT_IN);
+    return super.visitFieldDeclaration(node);
+  }
+
+  @override
+  Object visitFunctionDeclaration(FunctionDeclaration node) {
+    computer._addRegion_token(node.externalKeyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.propertyKeyword, HighlightType.BUILT_IN);
+    return super.visitFunctionDeclaration(node);
+  }
+
+  @override
+  Object visitFunctionTypeAlias(FunctionTypeAlias node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitFunctionTypeAlias(node);
+  }
+
+  @override
+  Object visitHideCombinator(HideCombinator node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitHideCombinator(node);
+  }
+
+  @override
+  Object visitImplementsClause(ImplementsClause node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitImplementsClause(node);
+  }
+
+  @override
+  Object visitImportDirective(ImportDirective node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.deferredToken, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.asToken, HighlightType.BUILT_IN);
+    return super.visitImportDirective(node);
+  }
+
+  @override
+  Object visitIntegerLiteral(IntegerLiteral node) {
+    computer._addRegion_node(node, HighlightType.LITERAL_INTEGER);
+    return super.visitIntegerLiteral(node);
+  }
+
+  @override
+  Object visitLibraryDirective(LibraryDirective node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitLibraryDirective(node);
+  }
+
+  @override
+  Object visitMethodDeclaration(MethodDeclaration node) {
+    computer._addRegion_token(node.externalKeyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.modifierKeyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.operatorKeyword, HighlightType.BUILT_IN);
+    computer._addRegion_token(node.propertyKeyword, HighlightType.BUILT_IN);
+    return super.visitMethodDeclaration(node);
+  }
+
+  @override
+  Object visitNativeClause(NativeClause node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitNativeClause(node);
+  }
+
+  @override
+  Object visitNativeFunctionBody(NativeFunctionBody node) {
+    computer._addRegion_token(node.nativeToken, HighlightType.BUILT_IN);
+    return super.visitNativeFunctionBody(node);
+  }
+
+  @override
+  Object visitPartDirective(PartDirective node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitPartDirective(node);
+  }
+
+  @override
+  Object visitPartOfDirective(PartOfDirective node) {
+    computer._addRegion_tokenStart_tokenEnd(node.partToken, node.ofToken, HighlightType.BUILT_IN);
+    return super.visitPartOfDirective(node);
+  }
+
+  @override
+  Object visitShowCombinator(ShowCombinator node) {
+    computer._addRegion_token(node.keyword, HighlightType.BUILT_IN);
+    return super.visitShowCombinator(node);
+  }
+
+  @override
+  Object visitSimpleIdentifier(SimpleIdentifier node) {
+    computer._addIdentifierRegion(node);
+    return super.visitSimpleIdentifier(node);
+  }
+
+  @override
+  Object visitSimpleStringLiteral(SimpleStringLiteral node) {
+    computer._addRegion_node(node, HighlightType.LITERAL_STRING);
+    return super.visitSimpleStringLiteral(node);
+  }
+
+  @override
+  Object visitTypeName(TypeName node) {
+    DartType type = node.type;
+    if (type != null) {
+      if (type.isDynamic && node.name.name == "dynamic") {
+        computer._addRegion_node(node, HighlightType.TYPE_NAME_DYNAMIC);
+        return null;
+      }
+    }
+    return super.visitTypeName(node);
+  }
+}
+
+
+/**
+ * Highlighting kinds constants.
+ */
+class HighlightType {
+  static const HighlightType ANNOTATION = const HighlightType('ANNOTATION');
+  static const HighlightType BUILT_IN = const HighlightType('BUILT_IN');
+  static const HighlightType CLASS = const HighlightType('CLASS');
+  static const HighlightType COMMENT_BLOCK = const HighlightType('COMMENT_BLOCK');
+  static const HighlightType COMMENT_DOCUMENTATION = const HighlightType('COMMENT_DOCUMENTATION');
+  static const HighlightType COMMENT_END_OF_LINE = const HighlightType('COMMENT_END_OF_LINE');
+  static const HighlightType CONSTRUCTOR = const HighlightType('CONSTRUCTOR');
+  static const HighlightType DIRECTIVE = const HighlightType('DIRECTIVE');
+  static const HighlightType DYNAMIC_TYPE = const HighlightType('DYNAMIC_TYPE');
+  static const HighlightType FIELD = const HighlightType('FIELD');
+  static const HighlightType FIELD_STATIC = const HighlightType('FIELD_STATIC');
+  static const HighlightType FUNCTION_DECLARATION = const HighlightType('FUNCTION_DECLARATION');
+  static const HighlightType FUNCTION = const HighlightType('FUNCTION');
+  static const HighlightType FUNCTION_TYPE_ALIAS = const HighlightType('FUNCTION_TYPE_ALIAS');
+  static const HighlightType GETTER_DECLARATION = const HighlightType('GETTER_DECLARATION');
+  static const HighlightType KEYWORD = const HighlightType('KEYWORD');
+  static const HighlightType IDENTIFIER_DEFAULT = const HighlightType('IDENTIFIER_DEFAULT');
+  static const HighlightType IMPORT_PREFIX = const HighlightType('IMPORT_PREFIX');
+  static const HighlightType LITERAL_BOOLEAN = const HighlightType('LITERAL_BOOLEAN');
+  static const HighlightType LITERAL_DOUBLE = const HighlightType('LITERAL_DOUBLE');
+  static const HighlightType LITERAL_INTEGER = const HighlightType('LITERAL_INTEGER');
+  static const HighlightType LITERAL_LIST = const HighlightType('LITERAL_LIST');
+  static const HighlightType LITERAL_MAP = const HighlightType('LITERAL_MAP');
+  static const HighlightType LITERAL_STRING = const HighlightType('LITERAL_STRING');
+  static const HighlightType LOCAL_VARIABLE_DECLARATION = const HighlightType('LOCAL_VARIABLE_DECLARATION');
+  static const HighlightType LOCAL_VARIABLE = const HighlightType('LOCAL_VARIABLE');
+  static const HighlightType METHOD_DECLARATION = const HighlightType('METHOD_DECLARATION');
+  static const HighlightType METHOD_DECLARATION_STATIC = const HighlightType('METHOD_DECLARATION_STATIC');
+  static const HighlightType METHOD = const HighlightType('METHOD');
+  static const HighlightType METHOD_STATIC = const HighlightType('METHOD_STATIC');
+  static const HighlightType PARAMETER = const HighlightType('PARAMETER');
+  static const HighlightType SETTER_DECLARATION = const HighlightType('SETTER_DECLARATION');
+  static const HighlightType TOP_LEVEL_VARIABLE = const HighlightType('TOP_LEVEL_VARIABLE');
+  static const HighlightType TYPE_NAME_DYNAMIC = const HighlightType('TYPE_NAME_DYNAMIC');
+  static const HighlightType TYPE_PARAMETER = const HighlightType('TYPE_PARAMETER');
+
+  final String name;
+
+  @override
+  String toString() => name;
+
+  const HighlightType(this.name);
+}
+
+
+/**
+ * A computer for navigation regions in a Dart [CompilationUnit].
+ */
+class DartUnitNavigationComputer {
+  final CompilationUnit _unit;
+
+  List<Map<String, Object>> _regions = [];
+
+  DartUnitNavigationComputer(this._unit);
+
+  /**
+   * Returns the computed navigation regions, not `null`.
+   */
+  List<Map<String, Object>> compute() {
+    _unit.accept(new _DartUnitNavigationComputerVisitor(this));
+    return new List.from(_regions);
+  }
+
+  void _addRegion(int offset, int length, Element element) {
+    Map<String, Object> target = _createTarget(element);
+    if (target == null) {
+      return;
+    }
+    _regions.add({
+      'offset': offset,
+      'length': length,
+      'targets': [target]
+    });
+  }
+
+  void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) {
+    int offset = a.offset;
+    int length = b.end - offset;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegion_nodeStart_nodeStart(AstNode a, AstNode b, Element element) {
+    int offset = a.offset;
+    int length = b.offset - offset;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) {
+    int offset = a.offset;
+    int length = b.end - offset;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegionForNode(AstNode node, Element element) {
+    int offset = node.offset;
+    int length = node.length;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegionForToken(Token token, Element element) {
+    int offset = token.offset;
+    int length = token.length;
+    _addRegion(offset, length, element);
+  }
+
+  /**
+   * Returns the JSON for the given [Element], maybe `null` if `null` was given.
+   */
+  Map<String, Object> _createTarget(Element element) {
+    if (element == null) {
+      return null;
+    }
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
+    // prepare Source
+    Source source = element.source;
+    if (source == null) {
+      return null;
+    }
+    // prepare location
+    int offset = element.nameOffset;
+    int length = element.displayName.length;
+    if (element is CompilationUnitElement) {
+      offset = 0;
+      length = 0;
+    }
+    // return as JSON
+    return {
+      'file': source.fullName,
+      'offset': offset,
+      'length': length,
+      'elementId': element.location.encoding
+    };
+  }
+}
+
+
+
+class _DartUnitNavigationComputerVisitor extends RecursiveAstVisitor {
+  final DartUnitNavigationComputer computer;
+
+  _DartUnitNavigationComputerVisitor(this.computer);
+
+  @override
+  visitAssignmentExpression(AssignmentExpression node) {
+    computer._addRegionForToken(node.operator, node.bestElement);
+    return super.visitAssignmentExpression(node);
+  }
+
+  @override
+  visitBinaryExpression(BinaryExpression node) {
+    computer._addRegionForToken(node.operator, node.bestElement);
+    return super.visitBinaryExpression(node);
+  }
+
+  @override
+  visitConstructorDeclaration(ConstructorDeclaration node) {
+    // associate constructor with "T" or "T.name"
+    {
+      AstNode firstNode = node.returnType;
+      AstNode lastNode = node.name;
+      if (lastNode == null) {
+        lastNode = firstNode;
+      }
+      if (firstNode != null && lastNode != null) {
+        computer._addRegion_nodeStart_nodeEnd(firstNode, lastNode, node.element);
+      }
+    }
+    return super.visitConstructorDeclaration(node);
+  }
+
+  @override
+  visitExportDirective(ExportDirective node) {
+    ExportElement exportElement = node.element;
+    if (exportElement != null) {
+      Element element = exportElement.exportedLibrary;
+      computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, element);
+    }
+    return super.visitExportDirective(node);
+  }
+
+  @override
+  visitImportDirective(ImportDirective node) {
+    ImportElement importElement = node.element;
+    if (importElement != null) {
+      Element element = importElement.importedLibrary;
+      computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, element);
+    }
+    return super.visitImportDirective(node);
+  }
+
+  @override
+  visitIndexExpression(IndexExpression node) {
+    computer._addRegionForToken(node.rightBracket, node.bestElement);
+    return super.visitIndexExpression(node);
+  }
+
+  @override
+  visitInstanceCreationExpression(InstanceCreationExpression node) {
+    computer._addRegion_nodeStart_nodeStart(node, node.argumentList, node.staticElement);
+    return super.visitInstanceCreationExpression(node);
+  }
+
+  @override
+  visitPartDirective(PartDirective node) {
+    computer._addRegion_tokenStart_nodeEnd(node.keyword, node.uri, node.element);
+    return super.visitPartDirective(node);
+  }
+
+  @override
+  visitPartOfDirective(PartOfDirective node) {
+    computer._addRegion_tokenStart_nodeEnd(node.keyword, node.libraryName, node.element);
+    return super.visitPartOfDirective(node);
+  }
+
+  @override
+  visitPostfixExpression(PostfixExpression node) {
+    computer._addRegionForToken(node.operator, node.bestElement);
+    return super.visitPostfixExpression(node);
+  }
+
+  @override
+  visitPrefixExpression(PrefixExpression node) {
+    computer._addRegionForToken(node.operator, node.bestElement);
+    return super.visitPrefixExpression(node);
+  }
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.parent is ConstructorDeclaration) {
+    } else {
+      computer._addRegionForNode(node, node.bestElement);
+    }
+    return super.visitSimpleIdentifier(node);
+  }
+}
diff --git a/pkg/analysis_server/test/analysis_abstract_test.dart b/pkg/analysis_server/test/analysis_abstract_test.dart
new file mode 100644
index 0000000..bc26d3e
--- /dev/null
+++ b/pkg/analysis_server/test/analysis_abstract_test.dart
@@ -0,0 +1,284 @@
+// 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.
+
+library test.domain.analysis.abstract;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/resource.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import 'mocks.dart';
+
+
+main() {
+}
+
+
+/**
+ * An abstract base for all 'analysis' domain tests.
+ */
+class AbstractAnalysisTest {
+  MockServerChannel serverChannel;
+  MemoryResourceProvider resourceProvider;
+  AnalysisServer server;
+  AnalysisDomainHandler handler;
+
+  Map<String, List<String>> analysisSubscriptions = {};
+
+  String projectPath = '/project';
+  String testFile = '/project/bin/test.dart';
+  String testCode;
+
+//  Map<String, List<AnalysisError>> filesErrors = {};
+//  Map<String, List<Map<String, Object>>> filesHighlights = {};
+//  Map<String, List<Map<String, Object>>> filesNavigation = {};
+
+
+  AbstractAnalysisTest() {
+  }
+
+  void setUp() {
+    serverChannel = new MockServerChannel();
+    resourceProvider = new MemoryResourceProvider();
+    server = new AnalysisServer(serverChannel, resourceProvider);
+    handler = new AnalysisDomainHandler(server);
+    // listen for notifications
+    Stream<Notification> notificationStream = serverChannel.notificationController.stream;
+    notificationStream.listen((Notification notification) {
+      processNotification(notification);
+    });
+    // create an empty project
+    _createEmptyProject();
+  }
+
+  void addAnalysisSubscription(AnalysisService service, String file) {
+    // add file to subscription
+    var files = analysisSubscriptions[service.name];
+    if (files == null) {
+      files = <String>[];
+      analysisSubscriptions[service.name] = files;
+    }
+    files.add(file);
+    // set subscriptions
+    Request request = new Request('0', METHOD_SET_ANALYSIS_SUBSCRIPTIONS);
+    request.setParameter(SUBSCRIPTIONS, analysisSubscriptions);
+    handleSuccessfulRequest(request);
+  }
+
+  void tearDown() {
+    server.done();
+    handler = null;
+    server = null;
+    resourceProvider = null;
+    serverChannel = null;
+  }
+
+  void processNotification(Notification notification) {
+//    if (notification.event == NOTIFICATION_ERRORS) {
+//      String file = notification.getParameter(FILE);
+//      List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
+//      filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
+//    }
+//    if (notification.event == NOTIFICATION_HIGHLIGHTS) {
+//      String file = notification.getParameter(FILE);
+//      filesHighlights[file] = notification.getParameter(REGIONS);
+//    }
+//    if (notification.event == NOTIFICATION_NAVIGATION) {
+//      String file = notification.getParameter(FILE);
+//      filesNavigation[file] = notification.getParameter(REGIONS);
+//    }
+  }
+
+  /**
+   * Returns a [Future] that completes when the [AnalysisServer] finishes
+   * all its scheduled tasks.
+   */
+  Future waitForTasksFinished() {
+    return waitForServerOperationsPerformed(server);
+  }
+
+  /**
+   * Returns the offset of [search] in [testCode].
+   * Fails if not found.
+   */
+  int findFileOffset(String path, String search) {
+    File file = resourceProvider.getResource(path) as File;
+    String code = file.createSource(UriKind.FILE_URI).contents.data;
+    int offset = code.indexOf(search);
+    expect(offset, isNot(-1), reason: '"$search" in\n$code');
+    return offset;
+  }
+
+  /**
+   * Returns the offset of [search] in [testCode].
+   * Fails if not found.
+   */
+  int findOffset(String search) {
+    int offset = testCode.indexOf(search);
+    expect(offset, isNot(-1));
+    return offset;
+  }
+
+//  /**
+//   * Returns [AnalysisError]s recorded for the given [file].
+//   * May be empty, but not `null`.
+//   */
+//  List<AnalysisError> getErrors(String file) {
+//    List<AnalysisError> errors = filesErrors[file];
+//    if (errors != null) {
+//      return errors;
+//    }
+//    return <AnalysisError>[];
+//  }
+//
+//  /**
+//   * Returns highlights recorded for the given [file].
+//   * May be empty, but not `null`.
+//   */
+//  List<Map<String, Object>> getHighlights(String file) {
+//    List<Map<String, Object>> highlights = filesHighlights[file];
+//    if (highlights != null) {
+//      return highlights;
+//    }
+//    return [];
+//  }
+//
+//  /**
+//   * Returns navigation regions recorded for the given [file].
+//   * May be empty, but not `null`.
+//   */
+//  List<Map<String, Object>> getNavigation(String file) {
+//    List<Map<String, Object>> navigation = filesNavigation[file];
+//    if (navigation != null) {
+//      return navigation;
+//    }
+//    return [];
+//  }
+//
+//  /**
+//   * Returns [AnalysisError]s recorded for the [testFile].
+//   * May be empty, but not `null`.
+//   */
+//  List<AnalysisError> getTestErrors() {
+//    return getErrors(testFile);
+//  }
+//
+//  /**
+//   * Returns highlights recorded for the given [testFile].
+//   * May be empty, but not `null`.
+//   */
+//  List<Map<String, Object>> getTestHighlights() {
+//    return getHighlights(testFile);
+//  }
+//
+//  /**
+//   * Returns navigation information recorded for the given [testFile].
+//   * May be empty, but not `null`.
+//   */
+//  List<Map<String, Object>> getTestNavigation() {
+//    return getNavigation(testFile);
+//  }
+
+  /**
+   * Creates an empty project `/project/`.
+   */
+  void _createEmptyProject() {
+    resourceProvider.newFolder(projectPath);
+    Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS);
+    request.setParameter(INCLUDED, [projectPath]);
+    request.setParameter(EXCLUDED, []);
+    handleSuccessfulRequest(request);
+  }
+
+//  /**
+//   * Creates a project with a single Dart file `/project/bin/test.dart` with
+//   * the given [code].
+//   */
+//  void createSingleFileProject(code) {
+//    this.testCode = _getCodeString(code);
+//    resourceProvider.newFolder('/project');
+//    resourceProvider.newFile(testFile, testCode);
+//    Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS);
+//    request.setParameter(INCLUDED, ['/project']);
+//    request.setParameter(EXCLUDED, []);
+//    handleSuccessfulRequest(request);
+//  }
+
+  String addFile(String path, String content) {
+    resourceProvider.newFile(path, content);
+    return path;
+  }
+
+  String addTestFile(String content) {
+    addFile(testFile, content);
+    this.testCode = content;
+    return testFile;
+  }
+
+  /**
+   * Validates that the given [request] is handled successfully.
+   */
+  void handleSuccessfulRequest(Request request) {
+    Response response = handler.handleRequest(request);
+    expect(response, isResponseSuccess('0'));
+  }
+
+  static String _getCodeString(code) {
+    if (code is List<String>) {
+      code = code.join('\n');
+    }
+    return code as String;
+  }
+}
+
+
+
+class AnalysisError {
+  final String file;
+  final String errorCode;
+  final int offset;
+  final int length;
+  final String message;
+  final String correction;
+  AnalysisError(this.file, this.errorCode, this.offset, this.length,
+      this.message, this.correction);
+
+  @override
+  String toString() {
+    return 'NotificationError(file=$file; errorCode=$errorCode; '
+        'offset=$offset; length=$length; message=$message)';
+  }
+}
+
+
+AnalysisError _jsonToAnalysisError(Map<String, Object> json) {
+  return new AnalysisError(
+      json['file'],
+      json['errorCode'],
+      json['offset'],
+      json['length'],
+      json['message'],
+      json['correction']);
+}
+
+
+int findIdentifierLength(String search) {
+  int length = 0;
+  while (length < search.length) {
+    int c = search.codeUnitAt(length);
+    if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+          c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+          c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+      break;
+    }
+    length++;
+  }
+  return length;
+}
diff --git a/pkg/analyzer_experimental/lib/src/services/runtime/coverage_impl.dart b/pkg/analyzer_experimental/lib/src/services/runtime/coverage_impl.dart
new file mode 100644
index 0000000..df37f7b
--- /dev/null
+++ b/pkg/analyzer_experimental/lib/src/services/runtime/coverage_impl.dart
@@ -0,0 +1,157 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A library for code coverage support for Dart.
+library runtime.coverage_impl;
+
+import "dart:io";
+
+import "package:logging/logging.dart" as log;
+import "package:pathos/path.dart" as po;
+
+import 'package:analyzer_experimental/src/generated/source.dart' show Source;
+import 'package:analyzer_experimental/src/generated/scanner.dart' show StringScanner;
+import 'package:analyzer_experimental/src/generated/parser.dart' show Parser;
+import 'package:analyzer_experimental/src/generated/ast.dart';
+import 'package:analyzer_experimental/src/generated/engine.dart' show RecordingErrorListener;
+
+
+log.Logger logger = log.Logger.root;
+
+/// Abstract server that listens requests and serves files, may be rewriting them.
+abstract class RewriteServer {
+  String _basePath;
+  RewriteServer(this._basePath);
+  void start() {
+    HttpServer.bind("127.0.0.1", 3445).then((HttpServer server) {
+      logger.info('RewriteServer is listening at: ${server.port}.');
+      server.listen((HttpRequest request) {
+        var response = request.response;
+        // Prepare path.
+        var path = _basePath + '/' + request.uri.path;
+        path = po.normalize(path);
+        logger.info('[$path] Requested.');
+        // May be serve using just path.
+        {
+          String content = rewritePathContent(path);
+          if (content != null) {
+            logger.info('[$path] Request served by path.');
+            response.write(content);
+            response.close();
+            return;
+          }
+        }
+        // Serve from file.
+        logger.info('[$path] Serving file.');
+        var file = new File(path);
+        file.exists().then((bool found) {
+          if (found) {
+            logger.finest('[$path] Found file.');
+            file.readAsString().then((String content) {
+              logger.finest('[$path] Got file content.');
+              var sw = new Stopwatch();
+              sw.start();
+              try {
+                content = rewriteFileContent(path, content);
+              } finally {
+                sw.stop();
+                logger.fine('[$path] Rewritten in ${sw.elapsedMilliseconds} ms.');
+              }
+              response.write(content);
+              response.close();
+            });
+          } else {
+            logger.severe('[$path] File not found.');
+            response.statusCode = HttpStatus.NOT_FOUND;
+            response.close();
+          }
+        });
+      });
+    });
+  }
+
+  /// Subclasses implement this method to rewrite the provided [code] of the file with [path].
+  /// Returns some content or `null` if file content should be requested.
+  String rewritePathContent(String path);
+
+  /// Subclasses implement this method to rewrite the provided [code] of the file with [path].
+  String rewriteFileContent(String path, String code);
+}
+
+/// Server that rewrites Dart code so that it reports execution of statements and other nodes.
+class CoverageServer extends RewriteServer {
+  CoverageServer(String basePath) : super(basePath);
+
+  String rewritePathContent(String path) {
+    if (path.endsWith('__coverage_impl.dart')) {
+      String implPath = po.joinAll([
+          po.dirname(new Options().script),
+          '..', 'lib', 'src', 'services', 'runtime', 'coverage_lib.dart']);
+      return new File(implPath).readAsStringSync();
+    }
+    return null;
+  }
+
+  String rewriteFileContent(String path, String code) {
+    if (po.extension(path).toLowerCase() != '.dart') return code;
+    if (path.contains('packages')) return code;
+    var unit = _parseCode(code);
+    var injector = new StringInjector(code);
+    // Inject coverage library import.
+    var directives = unit.directives;
+    if (directives.isNotEmpty && directives[0] is LibraryDirective) {
+      injector.inject(directives[0].end, 'import "__coverage_impl.dart" as __cc;');
+    } else {
+      throw new Exception('Only single library coverage is implemented.');
+    }
+    // Insert touch() invocations.
+    unit.accept(new InsertTouchInvocationsVisitor(injector));
+    // Done.
+    code = injector.code;
+    logger.finest('[$path] Rewritten content\n$code');
+    return code;
+  }
+
+  CompilationUnit _parseCode(String code) {
+    var source = null;
+    var errorListener = new RecordingErrorListener();
+    var parser = new Parser(source, errorListener);
+    var scanner = new StringScanner(source, code, errorListener);
+    var token = scanner.tokenize();
+    return parser.parseCompilationUnit(token);
+  }
+}
+
+/// The visitor that inserts `touch` method invocations.
+class InsertTouchInvocationsVisitor extends GeneralizingASTVisitor {
+  StringInjector injector;
+  InsertTouchInvocationsVisitor(this.injector);
+  visitStatement(Statement node) {
+    super.visitStatement(node);
+    var offset = node.end;
+    if (node is Block) {
+      offset--;
+    }
+    if (node is Block && node.parent is BlockFunctionBody) return null;
+    injector.inject(offset, '__cc.touch(${node.offset});');
+    return null;
+  }
+}
+
+/// Helper for injecting fragments into some existing [String].
+class StringInjector {
+  String code;
+  int _lastOffset = -1;
+  int _delta = 0;
+  StringInjector(this.code);
+  void inject(int offset, String fragment) {
+    if (offset < _lastOffset) {
+      throw new ArgumentError('Only forward inserts are supported, was $_lastOffset given $offset');
+    }
+    _lastOffset = offset;
+    offset += _delta;
+    code = code.substring(0, offset) + fragment + code.substring(offset);
+    _delta += fragment.length;
+  }
+}
\ No newline at end of file
diff --git a/pkg/analyzer_experimental/lib/src/services/runtime/coverage_lib.dart b/pkg/analyzer_experimental/lib/src/services/runtime/coverage_lib.dart
new file mode 100644
index 0000000..945b38f
--- /dev/null
+++ b/pkg/analyzer_experimental/lib/src/services/runtime/coverage_lib.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library is injected into the applications under coverage.
+library coverage_lib;
+
+/// Notifies that the object with the given [id] - statement, token, etc was executed.
+touch(int id) {
+  print('touch: $id');
+}
diff --git a/pkg/analyzer_experimental/lib/src/utils.dart b/pkg/analyzer_experimental/lib/src/utils.dart
new file mode 100644
index 0000000..2b5053e
--- /dev/null
+++ b/pkg/analyzer_experimental/lib/src/utils.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library utils;
+
+import 'dart:io';
+
+import 'package:pathos/path.dart' as pathos;
+
+/// Converts a local path string to a `file:` [Uri].
+Uri pathToFileUri(String pathString) {
+  pathString = pathos.absolute(pathString);
+  if (Platform.operatingSystem != 'windows') {
+    return Uri.parse('file://$pathString');
+  } else if (pathos.rootPrefix(pathString).startsWith('\\\\')) {
+    // Network paths become "file://hostname/path/to/file".
+    return Uri.parse('file:${pathString.replaceAll("\\", "/")}');
+  } else {
+    // Drive-letter paths become "file:///C:/path/to/file".
+    return Uri.parse('file:///${pathString.replaceAll("\\", "/")}');
+  }
+}
diff --git a/pkg/docgen/bin/generate_all_docs.sh b/pkg/docgen/bin/generate_all_docs.sh
new file mode 100755
index 0000000..8d5d82c
--- /dev/null
+++ b/pkg/docgen/bin/generate_all_docs.sh
@@ -0,0 +1,6 @@
+# A simple shell script to generate all docs for the sdk and pkg directories
+# into the docs folder in this directory.
+# TODO(alanknight): This should get subsumed into the python scripts
+dart --package-root=$DART_SDK/../packages/ docgen.dart --parse-sdk --json
+dart --old_gen_heap_size=1024 --package-root=$DART_SDK/../packages/ docgen.dart \
+  --package-root=$DART_SDK/../packages/ --append --json $DART_SDK/../../../pkg
diff --git a/pkg/matcher/lib/src/utils.dart b/pkg/matcher/lib/src/utils.dart
new file mode 100644
index 0000000..c2182c2
--- /dev/null
+++ b/pkg/matcher/lib/src/utils.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library matcher.utils;
+
+/**
+ * Returns the name of the type of [x], or "Unknown" if the type name can't be
+ * determined.
+ */
+String typeName(x) {
+  // dart2js blows up on some objects (e.g. window.navigator).
+  // So we play safe here.
+  try {
+    if (x == null) return "null";
+    var type = x.runtimeType.toString();
+    // TODO(nweiz): if the object's type is private, find a public superclass to
+    // display once there's a portable API to do that.
+    return type.startsWith("_") ? "?" : type;
+  } catch (e) {
+    return "?";
+  }
+}
+
+/**
+ * Returns [source] with any control characters replaced by their escape
+ * sequences.
+ *
+ * This doesn't add quotes to the string, but it does escape single quote
+ * characters so that single quotes can be applied externally.
+ */
+String escapeString(String source) =>
+    source.split("").map(_escapeChar).join("");
+
+/** Return the escaped form of a character [ch]. */
+String _escapeChar(String ch) {
+  if (ch == "'")
+    return "\\'";
+  else if (ch == '\n')
+    return '\\n';
+  else if (ch == '\r')
+    return '\\r';
+  else if (ch == '\t')
+    return '\\t';
+  else
+    return ch;
+}
+
+/** Indent each line in [str] by two spaces. */
+String indent(String str) =>
+  str.replaceAll(new RegExp("^", multiLine: true), "  ");
+
+/** A pair of values. */
+class Pair<E, F> {
+  E first;
+  F last;
+
+  Pair(this.first, this.last);
+
+  String toString() => '($first, $last)';
+
+  bool operator ==(other) {
+    if (other is! Pair) return false;
+    return other.first == first && other.last == last;
+  }
+
+  int get hashCode => first.hashCode ^ last.hashCode;
+}
+
diff --git a/pkg/matcher/test/matchers_test.dart b/pkg/matcher/test/matchers_test.dart
new file mode 100644
index 0000000..e74d048
--- /dev/null
+++ b/pkg/matcher/test/matchers_test.dart
@@ -0,0 +1,803 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for 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 matcher.test;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:matcher/matcher.dart';
+import 'package:unittest/unittest.dart' show test, group;
+
+import 'test_utils.dart';
+
+void main() {
+
+  initUtils();
+
+  // Core matchers
+
+  group('Core matchers', () {
+
+    test('isTrue', () {
+      shouldPass(true, isTrue);
+      shouldFail(false, isTrue, "Expected: true Actual: <false>");
+    });
+
+    test('isFalse', () {
+      shouldPass(false, isFalse);
+      shouldFail(10, isFalse, "Expected: false Actual: <10>");
+      shouldFail(true, isFalse, "Expected: false Actual: <true>");
+    });
+
+    test('isNull', () {
+      shouldPass(null, isNull);
+      shouldFail(false, isNull, "Expected: null Actual: <false>");
+    });
+
+    test('isNotNull', () {
+      shouldPass(false, isNotNull);
+      shouldFail(null, isNotNull, "Expected: not null Actual: <null>");
+    });
+
+    test('same', () {
+      var a = new Map();
+      var b = new Map();
+      shouldPass(a, same(a));
+      shouldFail(b, same(a), "Expected: same instance as {} Actual: {}");
+    });
+
+    test('equals', () {
+      var a = new Map();
+      var b = new Map();
+      shouldPass(a, equals(a));
+      shouldPass(a, equals(b));
+    });
+
+    test('anything', () {
+      var a = new Map();
+      shouldPass(0, anything);
+      shouldPass(null, anything);
+      shouldPass(a, anything);
+      shouldFail(a, isNot(anything), "Expected: not anything Actual: {}");
+    });
+
+    test('throws', () {
+      shouldFail(doesNotThrow, throws,
+          matches(
+              r"Expected: throws"
+              r"  Actual: <Closure(: \(\) => dynamic "
+              r"from Function 'doesNotThrow': static\.)?>"
+              r"   Which: did not throw"));
+      shouldPass(doesThrow, throws);
+      shouldFail(true, throws,
+          "Expected: throws"
+          "  Actual: <true>"
+          "   Which: is not a Function or Future");
+    });
+
+    test('throwsA', () {
+      shouldPass(doesThrow, throwsA(equals('X')));
+      shouldFail(doesThrow, throwsA(equals('Y')),
+          matches(
+              r"Expected: throws 'Y'"
+              r"  Actual: <Closure(: \(\) => dynamic "
+              r"from Function 'doesThrow': static\.)?>"
+              r"   Which: threw 'X'"));
+    });
+
+    test('returnsNormally', () {
+      shouldPass(doesNotThrow, returnsNormally);
+      shouldFail(doesThrow, returnsNormally,
+          matches(
+              r"Expected: return normally"
+              r"  Actual: <Closure(: \(\) => dynamic "
+              r"from Function 'doesThrow': static\.)?>"
+              r"   Which: threw 'X'"));
+    });
+
+
+    test('hasLength', () {
+      var a = new Map();
+      var b = new List();
+      shouldPass(a, hasLength(0));
+      shouldPass(b, hasLength(0));
+      shouldPass('a', hasLength(1));
+      shouldFail(0, hasLength(0), new PrefixMatcher(
+          "Expected: an object with length of <0> "
+          "Actual: <0> "
+          "Which: has no length property"));
+
+      b.add(0);
+      shouldPass(b, hasLength(1));
+      shouldFail(b, hasLength(2),
+          "Expected: an object with length of <2> "
+          "Actual: [0] "
+          "Which: has length of <1>");
+
+      b.add(0);
+      shouldFail(b, hasLength(1),
+          "Expected: an object with length of <1> "
+          "Actual: [0, 0] "
+          "Which: has length of <2>");
+      shouldPass(b, hasLength(2));
+    });
+
+    test('scalar type mismatch', () {
+      shouldFail('error', equals(5.1),
+          "Expected: <5.1> "
+          "Actual: 'error'");
+    });
+
+    test('nested type mismatch', () {
+      shouldFail(['error'], equals([5.1]),
+          "Expected: [5.1] "
+          "Actual: ['error'] "
+          "Which: was 'error' instead of <5.1> at location [0]");
+    });
+
+    test('doubly-nested type mismatch', () {
+      shouldFail([['error']], equals([[5.1]]),
+          "Expected: [[5.1]] "
+          "Actual: [['error']] "
+          "Which: was 'error' instead of <5.1> at location [0][0]");
+    });
+
+    test('doubly nested inequality', () {
+      var actual1 = [['foo', 'bar'], ['foo'], 3, []];
+      var expected1 = [['foo', 'bar'], ['foo'], 4, []];
+      var reason1 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+          "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+          "Which: was <3> instead of <4> at location [2]";
+
+      var actual2 = [['foo', 'barry'], ['foo'], 4, []];
+      var expected2 = [['foo', 'bar'], ['foo'], 4, []];
+      var reason2 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+          "Actual: [['foo', 'barry'], ['foo'], 4, []] "
+          "Which: was 'barry' instead of 'bar' at location [0][1]";
+
+      var actual3 = [['foo', 'bar'], ['foo'], 4, {'foo':'bar'}];
+      var expected3 = [['foo', 'bar'], ['foo'], 4, {'foo':'barry'}];
+      var reason3 = "Expected: [['foo', 'bar'], ['foo'], 4, {'foo': 'barry'}] "
+          "Actual: [['foo', 'bar'], ['foo'], 4, {'foo': 'bar'}] "
+          "Which: was 'bar' instead of 'barry' at location [3]['foo']";
+
+      shouldFail(actual1, equals(expected1), reason1);
+      shouldFail(actual2, equals(expected2), reason2);
+      shouldFail(actual3, equals(expected3), reason3);
+    });
+  });
+
+  group('Numeric Matchers', () {
+
+    test('greaterThan', () {
+      shouldPass(10, greaterThan(9));
+      shouldFail(9, greaterThan(10),
+        "Expected: a value greater than <10> "
+        "Actual: <9> "
+        "Which: is not a value greater than <10>");
+    });
+
+    test('greaterThanOrEqualTo', () {
+      shouldPass(10, greaterThanOrEqualTo(10));
+      shouldFail(9, greaterThanOrEqualTo(10),
+        "Expected: a value greater than or equal to <10> "
+        "Actual: <9> "
+        "Which: is not a value greater than or equal to <10>");
+    });
+
+    test('lessThan', () {
+      shouldFail(10, lessThan(9),
+          "Expected: a value less than <9> "
+          "Actual: <10> "
+          "Which: is not a value less than <9>");
+      shouldPass(9, lessThan(10));
+    });
+
+    test('lessThanOrEqualTo', () {
+      shouldPass(10, lessThanOrEqualTo(10));
+      shouldFail(11, lessThanOrEqualTo(10),
+        "Expected: a value less than or equal to <10> "
+        "Actual: <11> "
+        "Which: is not a value less than or equal to <10>");
+    });
+
+    test('isZero', () {
+      shouldPass(0, isZero);
+      shouldFail(1, isZero,
+          "Expected: a value equal to <0> "
+          "Actual: <1> "
+          "Which: is not a value equal to <0>");
+    });
+
+    test('isNonZero', () {
+      shouldFail(0, isNonZero,
+          "Expected: a value not equal to <0> "
+          "Actual: <0> "
+          "Which: is not a value not equal to <0>");
+      shouldPass(1, isNonZero);
+    });
+
+    test('isPositive', () {
+      shouldFail(-1, isPositive,
+          "Expected: a positive value "
+          "Actual: <-1> "
+          "Which: is not a positive value");
+      shouldFail(0, isPositive,
+          "Expected: a positive value "
+          "Actual: <0> "
+          "Which: is not a positive value");
+      shouldPass(1, isPositive);
+    });
+
+    test('isNegative', () {
+      shouldPass(-1, isNegative);
+      shouldFail(0, isNegative,
+          "Expected: a negative value "
+          "Actual: <0> "
+          "Which: is not a negative value");
+    });
+
+    test('isNonPositive', () {
+      shouldPass(-1, isNonPositive);
+      shouldPass(0, isNonPositive);
+      shouldFail(1, isNonPositive,
+          "Expected: a non-positive value "
+          "Actual: <1> "
+          "Which: is not a non-positive value");
+    });
+
+    test('isNonNegative', () {
+      shouldPass(1, isNonNegative);
+      shouldPass(0, isNonNegative);
+      shouldFail(-1, isNonNegative,
+        "Expected: a non-negative value "
+        "Actual: <-1> "
+        "Which: is not a non-negative value");
+    });
+
+    test('closeTo', () {
+      shouldPass(0, closeTo(0, 1));
+      shouldPass(-1, closeTo(0, 1));
+      shouldPass(1, closeTo(0, 1));
+      shouldFail(1.001, closeTo(0, 1),
+          "Expected: a numeric value within <1> of <0> "
+          "Actual: <1.001> "
+          "Which: differs by <1.001>");
+      shouldFail(-1.001, closeTo(0, 1),
+          "Expected: a numeric value within <1> of <0> "
+          "Actual: <-1.001> "
+          "Which: differs by <1.001>");
+    });
+
+    test('inInclusiveRange', () {
+      shouldFail(-1, inInclusiveRange(0,2),
+          "Expected: be in range from 0 (inclusive) to 2 (inclusive) "
+          "Actual: <-1>");
+      shouldPass(0, inInclusiveRange(0,2));
+      shouldPass(1, inInclusiveRange(0,2));
+      shouldPass(2, inInclusiveRange(0,2));
+      shouldFail(3, inInclusiveRange(0,2),
+          "Expected: be in range from 0 (inclusive) to 2 (inclusive) "
+          "Actual: <3>");
+    });
+
+    test('inExclusiveRange', () {
+      shouldFail(0, inExclusiveRange(0,2),
+          "Expected: be in range from 0 (exclusive) to 2 (exclusive) "
+          "Actual: <0>");
+      shouldPass(1, inExclusiveRange(0,2));
+      shouldFail(2, inExclusiveRange(0,2),
+          "Expected: be in range from 0 (exclusive) to 2 (exclusive) "
+          "Actual: <2>");
+    });
+
+    test('inOpenClosedRange', () {
+      shouldFail(0, inOpenClosedRange(0,2),
+          "Expected: be in range from 0 (exclusive) to 2 (inclusive) "
+          "Actual: <0>");
+      shouldPass(1, inOpenClosedRange(0,2));
+      shouldPass(2, inOpenClosedRange(0,2));
+    });
+
+    test('inClosedOpenRange', () {
+      shouldPass(0, inClosedOpenRange(0,2));
+      shouldPass(1, inClosedOpenRange(0,2));
+      shouldFail(2, inClosedOpenRange(0,2),
+          "Expected: be in range from 0 (inclusive) to 2 (exclusive) "
+          "Actual: <2>");
+    });
+  });
+
+  group('String Matchers', () {
+
+    test('isEmpty', () {
+      shouldPass('', isEmpty);
+      shouldFail(null, isEmpty,
+          "Expected: empty Actual: <null>");
+      shouldFail(0, isEmpty,
+          "Expected: empty Actual: <0>");
+      shouldFail('a', isEmpty, "Expected: empty Actual: 'a'");
+    });
+
+    test('equalsIgnoringCase', () {
+      shouldPass('hello', equalsIgnoringCase('HELLO'));
+      shouldFail('hi', equalsIgnoringCase('HELLO'),
+          "Expected: 'HELLO' ignoring case Actual: 'hi'");
+    });
+
+    test('equalsIgnoringWhitespace', () {
+      shouldPass(' hello   world  ', equalsIgnoringWhitespace('hello world'));
+      shouldFail(' helloworld  ', equalsIgnoringWhitespace('hello world'),
+          "Expected: 'hello world' ignoring whitespace "
+          "Actual: ' helloworld ' "
+          "Which: is 'helloworld' with whitespace compressed");
+    });
+
+    test('startsWith', () {
+      shouldPass('hello', startsWith(''));
+      shouldPass('hello', startsWith('hell'));
+      shouldPass('hello', startsWith('hello'));
+      shouldFail('hello', startsWith('hello '),
+          "Expected: a string starting with 'hello ' "
+          "Actual: 'hello'");
+    });
+
+    test('endsWith', () {
+      shouldPass('hello', endsWith(''));
+      shouldPass('hello', endsWith('lo'));
+      shouldPass('hello', endsWith('hello'));
+      shouldFail('hello', endsWith(' hello'),
+          "Expected: a string ending with ' hello' "
+          "Actual: 'hello'");
+    });
+
+    test('contains', () {
+      shouldPass('hello', contains(''));
+      shouldPass('hello', contains('h'));
+      shouldPass('hello', contains('o'));
+      shouldPass('hello', contains('hell'));
+      shouldPass('hello', contains('hello'));
+      shouldFail('hello', contains(' '),
+          "Expected: contains ' ' Actual: 'hello'");
+    });
+
+    test('stringContainsInOrder', () {
+      shouldPass('goodbye cruel world', stringContainsInOrder(['']));
+      shouldPass('goodbye cruel world', stringContainsInOrder(['goodbye']));
+      shouldPass('goodbye cruel world', stringContainsInOrder(['cruel']));
+      shouldPass('goodbye cruel world', stringContainsInOrder(['world']));
+      shouldPass('goodbye cruel world',
+                 stringContainsInOrder(['good', 'bye', 'world']));
+      shouldPass('goodbye cruel world',
+                 stringContainsInOrder(['goodbye', 'cruel']));
+      shouldPass('goodbye cruel world',
+                 stringContainsInOrder(['cruel', 'world']));
+      shouldPass('goodbye cruel world',
+        stringContainsInOrder(['goodbye', 'cruel', 'world']));
+      shouldFail('goodbye cruel world',
+        stringContainsInOrder(['goo', 'cruel', 'bye']),
+        "Expected: a string containing 'goo', 'cruel', 'bye' in order "
+        "Actual: 'goodbye cruel world'");
+    });
+
+    test('matches', () {
+      shouldPass('c0d', matches('[a-z][0-9][a-z]'));
+      shouldPass('c0d', matches(new RegExp('[a-z][0-9][a-z]')));
+      shouldFail('cOd', matches('[a-z][0-9][a-z]'),
+          "Expected: match '[a-z][0-9][a-z]' Actual: 'cOd'");
+    });
+  });
+
+  group('Iterable Matchers', () {
+
+    test('isEmpty', () {
+      shouldPass([], isEmpty);
+      shouldFail([1], isEmpty, "Expected: empty Actual: [1]");
+    });
+
+    test('contains', () {
+      var d = [1, 2];
+      shouldPass(d, contains(1));
+      shouldFail(d, contains(0), "Expected: contains <0> "
+          "Actual: [1, 2]");
+    });
+
+    test('equals with matcher element', () {
+      var d = ['foo', 'bar'];
+      shouldPass(d, equals(['foo', startsWith('ba')]));
+      shouldFail(d, equals(['foo', endsWith('ba')]),
+          "Expected: ['foo', <a string ending with 'ba'>] "
+          "Actual: ['foo', 'bar'] "
+          "Which: does not match a string ending with 'ba' at location [1]");
+    });
+
+    test('isIn', () {
+      var d = [1, 2];
+      shouldPass(1, isIn(d));
+      shouldFail(0, isIn(d), "Expected: is in [1, 2] Actual: <0>");
+    });
+
+    test('everyElement', () {
+      var d = [1, 2];
+      var e = [1, 1, 1];
+      shouldFail(d, everyElement(1),
+          "Expected: every element(<1>) "
+          "Actual: [1, 2] "
+          "Which: has value <2> which doesn't match <1> at index 1");
+      shouldPass(e, everyElement(1));
+    });
+
+    test('nested everyElement', () {
+      var d = [['foo', 'bar'], ['foo'], []];
+      var e = [['foo', 'bar'], ['foo'], 3, []];
+      shouldPass(d, everyElement(anyOf(isEmpty, contains('foo'))));
+      shouldFail(d, everyElement(everyElement(equals('foo'))),
+          "Expected: every element(every element('foo')) "
+          "Actual: [['foo', 'bar'], ['foo'], []] "
+          "Which: has value ['foo', 'bar'] which has value 'bar' "
+          "which is different. Expected: foo Actual: bar ^ "
+          "Differ at offset 0 at index 1 at index 0");
+      shouldFail(d, everyElement(allOf(hasLength(greaterThan(0)),
+          contains('foo'))),
+           "Expected: every element((an object with length of a value "
+           "greater than <0> and contains 'foo')) "
+           "Actual: [['foo', 'bar'], ['foo'], []] "
+           "Which: has value [] which has length of <0> at index 2");
+      shouldFail(d, everyElement(allOf(contains('foo'),
+          hasLength(greaterThan(0)))),
+          "Expected: every element((contains 'foo' and "
+          "an object with length of a value greater than <0>)) "
+          "Actual: [['foo', 'bar'], ['foo'], []] "
+          "Which: has value [] which doesn't match (contains 'foo' and "
+          "an object with length of a value greater than <0>) at index 2");
+      shouldFail(e, everyElement(allOf(contains('foo'),
+          hasLength(greaterThan(0)))),
+          "Expected: every element((contains 'foo' and an object with "
+          "length of a value greater than <0>)) "
+          "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+          "Which: has value <3> which is not a string, map or iterable "
+          "at index 2");
+    });
+
+    test('anyElement', () {
+      var d = [1, 2];
+      var e = [1, 1, 1];
+      shouldPass(d, anyElement(2));
+      shouldFail(e, anyElement(2),
+          "Expected: some element <2> Actual: [1, 1, 1]");
+    });
+
+    test('orderedEquals', () {
+      shouldPass([null], orderedEquals([null]));
+      var d = [1, 2];
+      shouldPass(d, orderedEquals([1, 2]));
+      shouldFail(d, orderedEquals([2, 1]),
+          "Expected: equals [2, 1] ordered "
+          "Actual: [1, 2] "
+          "Which: was <1> instead of <2> at location [0]");
+    });
+
+    test('unorderedEquals', () {
+      var d = [1, 2];
+      shouldPass(d, unorderedEquals([2, 1]));
+      shouldFail(d, unorderedEquals([1]),
+          "Expected: equals [1] unordered "
+          "Actual: [1, 2] "
+          "Which: has too many elements (2 > 1)");
+      shouldFail(d, unorderedEquals([3, 2, 1]),
+          "Expected: equals [3, 2, 1] unordered "
+          "Actual: [1, 2] "
+          "Which: has too few elements (2 < 3)");
+      shouldFail(d, unorderedEquals([3, 1]),
+          "Expected: equals [3, 1] unordered "
+          "Actual: [1, 2] "
+          "Which: has no match for <3> at index 0");
+    });
+
+    test('unorderedMatchess', () {
+      var d = [1, 2];
+      shouldPass(d, unorderedMatches([2, 1]));
+      shouldPass(d, unorderedMatches([greaterThan(1), greaterThan(0)]));
+      shouldFail(d, unorderedMatches([greaterThan(0)]),
+          "Expected: matches [a value greater than <0>] unordered "
+          "Actual: [1, 2] "
+          "Which: has too many elements (2 > 1)");
+      shouldFail(d, unorderedMatches([3, 2, 1]),
+          "Expected: matches [<3>, <2>, <1>] unordered "
+          "Actual: [1, 2] "
+          "Which: has too few elements (2 < 3)");
+      shouldFail(d, unorderedMatches([3, 1]),
+          "Expected: matches [<3>, <1>] unordered "
+          "Actual: [1, 2] "
+          "Which: has no match for <3> at index 0");
+      shouldFail(d, unorderedMatches([greaterThan(3), greaterThan(0)]),
+          "Expected: matches [a value greater than <3>, a value greater than "
+              "<0>] unordered "
+          "Actual: [1, 2] "
+          "Which: has no match for a value greater than <3> at index 0");
+    });
+
+    test('pairwise compare', () {
+      var c = [1, 2];
+      var d = [1, 2, 3];
+      var e = [1, 4, 9];
+      shouldFail('x', pairwiseCompare(e, (e,a) => a <= e,
+          "less than or equal"),
+          "Expected: pairwise less than or equal [1, 4, 9] "
+          "Actual: 'x' "
+          "Which: is not an Iterable");
+      shouldFail(c, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"),
+          "Expected: pairwise less than or equal [1, 4, 9] "
+          "Actual: [1, 2] "
+          "Which: has length 2 instead of 3");
+      shouldPass(d, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"));
+      shouldFail(d, pairwiseCompare(e, (e,a) => a < e, "less than"),
+          "Expected: pairwise less than [1, 4, 9] "
+          "Actual: [1, 2, 3] "
+          "Which: has <1> which is not less than <1> at index 0");
+      shouldPass(d, pairwiseCompare(e, (e,a) => a * a == e, "square root of"));
+      shouldFail(d, pairwiseCompare(e, (e,a) => a + a == e, "double"),
+          "Expected: pairwise double [1, 4, 9] "
+          "Actual: [1, 2, 3] "
+          "Which: has <1> which is not double <1> at index 0");
+    });
+  });
+
+  group('Map Matchers', () {
+
+    test('isEmpty', () {
+      var a = new Map();
+      shouldPass({}, isEmpty);
+      shouldPass(a, isEmpty);
+      a['foo'] = 'bar';
+      shouldFail(a, isEmpty, "Expected: empty "
+          "Actual: {'foo': 'bar'}");
+    });
+
+    test('equals', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      var b = new Map();
+      b['foo'] = 'bar';
+      var c = new Map();
+      c['bar'] = 'foo';
+      shouldPass(a, equals(b));
+      shouldFail(b, equals(c),
+          "Expected: {'bar': 'foo'} "
+          "Actual: {'foo': 'bar'} "
+          "Which: is missing map key 'bar'");
+    });
+
+    test('equals with different lengths', () {
+      var a = new LinkedHashMap();
+      a['foo'] = 'bar';
+      var b = new LinkedHashMap();
+      b['foo'] = 'bar';
+      b['bar'] = 'foo';
+      var c = new LinkedHashMap();
+      c['bar'] = 'foo';
+      c['barrista'] = 'caffeine';
+      shouldFail(a, equals(b),
+          "Expected: {'foo': 'bar', 'bar': 'foo'} "
+          "Actual: {'foo': 'bar'} "
+          "Which: has different length and is missing map key 'bar'");
+      shouldFail(b, equals(a),
+          "Expected: {'foo': 'bar'} "
+          "Actual: {'foo': 'bar', 'bar': 'foo'} "
+          "Which: has different length and has extra map key 'bar'");
+      shouldFail(b, equals(c),
+          "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Actual: {'foo': 'bar', 'bar': 'foo'} "
+          "Which: is missing map key 'barrista'");
+      shouldFail(c, equals(b),
+          "Expected: {'foo': 'bar', 'bar': 'foo'} "
+          "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Which: is missing map key 'foo'");
+      shouldFail(a, equals(c),
+          "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Actual: {'foo': 'bar'} "
+          "Which: has different length and is missing map key 'bar'");
+      shouldFail(c, equals(a),
+          "Expected: {'foo': 'bar'} "
+          "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Which: has different length and is missing map key 'foo'");
+    });
+
+    test('equals with matcher value', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      shouldPass(a, equals({'foo': startsWith('ba')}));
+      shouldFail(a, equals({'foo': endsWith('ba')}),
+          "Expected: {'foo': <a string ending with 'ba'>} "
+          "Actual: {'foo': 'bar'} "
+          "Which: does not match a string ending with 'ba' "
+              "at location ['foo']");
+    });
+
+    test('contains', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      var b = new Map();
+      shouldPass(a, contains('foo'));
+      shouldFail(b, contains('foo'),
+          "Expected: contains 'foo' Actual: {}");
+      shouldFail(10, contains('foo'),
+          "Expected: contains 'foo' Actual: <10> "
+          "Which: is not a string, map or iterable");
+    });
+
+    test('containsValue', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      shouldPass(a, containsValue('bar'));
+      shouldFail(a, containsValue('ba'),
+          "Expected: contains value 'ba' "
+          "Actual: {'foo': 'bar'}");
+    });
+
+    test('containsPair', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      shouldPass(a, containsPair('foo', 'bar'));
+      shouldFail(a, containsPair('foo', 'ba'),
+          "Expected: contains pair 'foo' => 'ba' "
+          "Actual: {'foo': 'bar'} "
+          "Which: is different. Both strings start the same, but "
+          "the given value also has the following trailing characters: r");
+      shouldFail(a, containsPair('fo', 'bar'),
+          "Expected: contains pair 'fo' => 'bar' "
+          "Actual: {'foo': 'bar'} "
+          "Which: doesn't contain key 'fo'");
+    });
+
+    test('hasLength', () {
+      var a = new Map();
+      a['foo'] = 'bar';
+      var b = new Map();
+      shouldPass(a, hasLength(1));
+      shouldFail(b, hasLength(1),
+          "Expected: an object with length of <1> "
+          "Actual: {} "
+          "Which: has length of <0>");
+    });
+  });
+
+  group('Operator Matchers', () {
+
+    test('anyOf', () {
+      shouldFail(0, anyOf([equals(1), equals(2)]),
+          "Expected: (<1> or <2>) Actual: <0>");
+      shouldPass(1, anyOf([equals(1), equals(2)]));
+    });
+
+    test('allOf', () {
+      shouldPass(1, allOf([lessThan(10), greaterThan(0)]));
+      shouldFail(-1, allOf([lessThan(10), greaterThan(0)]),
+          "Expected: (a value less than <10> and a value greater than <0>) "
+          "Actual: <-1> "
+          "Which: is not a value greater than <0>");
+    });
+  });
+
+  group('Future Matchers', () {
+
+    test('completes - unexpected error', () {
+      var completer = new Completer();
+      completer.completeError('X');
+      shouldFail(completer.future, completes,
+          contains('Expected future to complete successfully, '
+                   'but it failed with X'),
+          isAsync: true);
+    });
+
+    test('completes - successfully', () {
+      var completer = new Completer();
+      completer.complete('1');
+      shouldPass(completer.future, completes, isAsync: true);
+    });
+
+    test('throws - unexpected to see normal completion', () {
+      var completer = new Completer();
+      completer.complete('1');
+      shouldFail(completer.future, throws,
+        contains("Expected future to fail, but succeeded with '1'"),
+        isAsync: true);
+    });
+
+    test('throws - expected to see exception', () {
+      var completer = new Completer();
+      completer.completeError('X');
+      shouldPass(completer.future, throws, isAsync: true);
+    });
+
+    test('throws - expected to see exception thrown later on', () {
+      var completer = new Completer();
+      var chained = completer.future.then((_) { throw 'X'; });
+      shouldPass(chained, throws, isAsync: true);
+      completer.complete('1');
+    });
+
+    test('throwsA - unexpected normal completion', () {
+      var completer = new Completer();
+      completer.complete('1');
+      shouldFail(completer.future, throwsA(equals('X')),
+        contains("Expected future to fail, but succeeded with '1'"),
+        isAsync: true);
+    });
+
+    test('throwsA - correct error', () {
+      var completer = new Completer();
+      completer.completeError('X');
+      shouldPass(completer.future, throwsA(equals('X')), isAsync: true);
+    });
+
+    test('throwsA - wrong error', () {
+      var completer = new Completer();
+      completer.completeError('X');
+      shouldFail(completer.future, throwsA(equals('Y')),
+          "Expected: 'Y' Actual: 'X' "
+          "Which: is different. "
+          "Expected: Y Actual: X ^ Differ at offset 0",
+          isAsync: true);
+    });
+  });
+
+  group('Predicate Matchers', () {
+    test('isInstanceOf', () {
+      shouldFail(0, predicate((x) => x is String, "an instance of String"),
+          "Expected: an instance of String Actual: <0>");
+      shouldPass('cow', predicate((x) => x is String, "an instance of String"));
+    });
+  });
+
+  group('exception/error matchers', () {
+    // TODO(gram): extend this to more types; for now this is just
+    // the types being added in this CL.
+
+    test('throwsCyclicInitializationError', () {
+      expect(() => _Bicycle.foo, throwsCyclicInitializationError);
+    });
+
+    test('throwsAbstractClassInstantiationError', () {
+      expect(() => new _AbstractClass(), throwsAbstractClassInstantiationError);
+    });
+
+    test('throwsConcurrentModificationError', () {
+      expect(() {
+        var a = { 'foo': 'bar' };
+        for (var k in a.keys) {
+          a.remove(k);
+        }
+      }, throwsConcurrentModificationError);
+      });
+
+    test('throwsNullThrownError', () {
+      expect(() => throw null, throwsNullThrownError);
+    });
+
+    test('throwsFallThroughError', () {
+      expect(() {
+        var a = 0;
+        switch (a) {
+          case 0:
+            a += 1;
+          case 1:
+            return;
+        }
+      }, throwsFallThroughError);
+    });
+  });
+}
+
+class _Bicycle {
+  static final foo = bar();
+
+  static bar() {
+    return foo + 1;
+  }
+}
+
+abstract class _AbstractClass {
+}
diff --git a/runtime/bin/vmservice/client/lib/src/elements/response_viewer.dart b/runtime/bin/vmservice/client/lib/src/elements/response_viewer.dart
new file mode 100644
index 0000000..a541b35
--- /dev/null
+++ b/runtime/bin/vmservice/client/lib/src/elements/response_viewer.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library response_viewer_element;
+
+import 'observatory_element.dart';
+import 'package:observatory/app.dart';
+import 'package:polymer/polymer.dart';
+
+@CustomTag('response-viewer')
+class ResponseViewerElement extends ObservatoryElement {
+  @published ObservatoryApplication app;
+  ResponseViewerElement.created() : super.created();
+}
diff --git a/runtime/bin/vmservice/client/lib/src/elements/response_viewer.html b/runtime/bin/vmservice/client/lib/src/elements/response_viewer.html
new file mode 100644
index 0000000..230120a
--- /dev/null
+++ b/runtime/bin/vmservice/client/lib/src/elements/response_viewer.html
@@ -0,0 +1,10 @@
+<head>
+  <link rel="import" href="observatory_element.html">
+  <link rel="import" href="service_view.html">
+</head>
+<polymer-element name="response-viewer" extends="observatory-element">
+  <template>
+    <service-view object="{{ app.response }}"></service-view>
+  </template>
+  <script type="application/dart" src="response_viewer.dart"></script>
+</polymer-element>
\ No newline at end of file
diff --git a/site/try/create_manifest.sh b/site/try/create_manifest.sh
old mode 100644
new mode 100755
diff --git a/tests/html/path_observer_test.dart b/tests/html/path_observer_test.dart
new file mode 100644
index 0000000..d6db89b
--- /dev/null
+++ b/tests/html/path_observer_test.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html' show PathObserver;
+import 'package:unittest/html_config.dart';
+import 'package:mdv_observe/mdv_observe.dart';
+import 'package:unittest/unittest.dart';
+
+// This file contains code ported from:
+// https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
+
+main() {
+  useHtmlConfiguration();
+  group('PathObserver', observePathTests);
+}
+
+observePath(obj, path) => new PathObserver(obj, path);
+
+sym(x) => new Symbol(x);
+
+toSymbolMap(Map map) {
+  var result = new ObservableMap.linked();
+  map.forEach((key, value) {
+    if (value is Map) value = toSymbolMap(value);
+    result[new Symbol(key)] = value;
+  });
+  return result;
+}
+
+observePathTests() {
+
+  test('Degenerate Values', () {
+    expect(observePath(null, '').value, null);
+    expect(observePath(123, '').value, 123);
+    expect(observePath(123, 'foo.bar.baz').value, null);
+
+    // shouldn't throw:
+    observePath(123, '').values.listen((_) {}).cancel();
+    observePath(null, '').value = null;
+    observePath(123, '').value = 42;
+    observePath(123, 'foo.bar.baz').value = 42;
+
+    var foo = {};
+    expect(observePath(foo, '').value, foo);
+
+    foo = new Object();
+    expect(observePath(foo, '').value, foo);
+
+    expect(observePath(foo, 'a/3!').value, null);
+  });
+
+  test('get value at path ObservableBox', () {
+    var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
+
+    expect(observePath(obj, '').value, obj);
+    expect(observePath(obj, 'value').value, obj.value);
+    expect(observePath(obj, 'value.value').value, obj.value.value);
+    expect(observePath(obj, 'value.value.value').value, 1);
+
+    obj.value.value.value = 2;
+    expect(observePath(obj, 'value.value.value').value, 2);
+
+    obj.value.value = new ObservableBox(3);
+    expect(observePath(obj, 'value.value.value').value, 3);
+
+    obj.value = new ObservableBox(4);
+    expect(observePath(obj, 'value.value.value').value, null);
+    expect(observePath(obj, 'value.value').value, 4);
+  });
+
+
+  test('get value at path ObservableMap', () {
+    var obj = toSymbolMap({'a': {'b': {'c': 1}}});
+
+    expect(observePath(obj, '').value, obj);
+    expect(observePath(obj, 'a').value, obj[sym('a')]);
+    expect(observePath(obj, 'a.b').value, obj[sym('a')][sym('b')]);
+    expect(observePath(obj, 'a.b.c').value, 1);
+
+    obj[sym('a')][sym('b')][sym('c')] = 2;
+    expect(observePath(obj, 'a.b.c').value, 2);
+
+    obj[sym('a')][sym('b')] = toSymbolMap({'c': 3});
+    expect(observePath(obj, 'a.b.c').value, 3);
+
+    obj[sym('a')] = toSymbolMap({'b': 4});
+    expect(observePath(obj, 'a.b.c').value, null);
+    expect(observePath(obj, 'a.b').value, 4);
+  });
+
+  test('set value at path', () {
+    var obj = toSymbolMap({});
+    observePath(obj, 'foo').value = 3;
+    expect(obj[sym('foo')], 3);
+
+    var bar = toSymbolMap({ 'baz': 3 });
+    observePath(obj, 'bar').value = bar;
+    expect(obj[sym('bar')], bar);
+
+    observePath(obj, 'bar.baz.bat').value = 'not here';
+    expect(observePath(obj, 'bar.baz.bat').value, null);
+  });
+
+  test('set value back to same', () {
+    var obj = toSymbolMap({});
+    var path = observePath(obj, 'foo');
+    var values = [];
+    path.values.listen((v) { values.add(v); });
+
+    path.value = 3;
+    expect(obj[sym('foo')], 3);
+    expect(path.value, 3);
+
+    observePath(obj, 'foo').value = 2;
+    deliverChangeRecords();
+    expect(path.value, 2);
+    expect(observePath(obj, 'foo').value, 2);
+
+    observePath(obj, 'foo').value = 3;
+    deliverChangeRecords();
+    expect(path.value, 3);
+
+    deliverChangeRecords();
+    expect(values, [2, 3]);
+  });
+
+  test('Observe and Unobserve - Paths', () {
+    var arr = toSymbolMap({});
+
+    arr[sym('foo')] = 'bar';
+    var fooValues = [];
+    var fooPath = observePath(arr, 'foo');
+    var fooSub = fooPath.values.listen((v) {
+      fooValues.add(v);
+    });
+    arr[sym('foo')] = 'baz';
+    arr[sym('bat')] = 'bag';
+    var batValues = [];
+    var batPath = observePath(arr, 'bat');
+    var batSub = batPath.values.listen((v) {
+      batValues.add(v);
+    });
+
+    deliverChangeRecords();
+    expect(fooValues, ['baz']);
+    expect(batValues, []);
+
+    arr[sym('foo')] = 'bar';
+    fooSub.cancel();
+    arr[sym('bat')] = 'boo';
+    batSub.cancel();
+    arr[sym('bat')] = 'boot';
+
+    deliverChangeRecords();
+    expect(fooValues, ['baz']);
+    expect(batValues, []);
+  });
+
+  test('Path Value With Indices', () {
+    var model = toObservable([]);
+    observePath(model, '0').values.listen(expectAsync1((v) {
+      expect(v, 123);
+    }));
+    model.add(123);
+  });
+
+  test('Path Observation', () {
+    var model = new TestModel(const Symbol('a'),
+        new TestModel(const Symbol('b'),
+            new TestModel(const Symbol('c'), 'hello, world')));
+
+    var path = observePath(model, 'a.b.c');
+    var lastValue = null;
+    var sub = path.values.listen((v) { lastValue = v; });
+
+    model.value.value.value = 'hello, mom';
+
+    expect(lastValue, null);
+    deliverChangeRecords();
+    expect(lastValue, 'hello, mom');
+
+    model.value.value = new TestModel(const Symbol('c'), 'hello, dad');
+    deliverChangeRecords();
+    expect(lastValue, 'hello, dad');
+
+    model.value = new TestModel(const Symbol('b'),
+        new TestModel(const Symbol('c'), 'hello, you'));
+    deliverChangeRecords();
+    expect(lastValue, 'hello, you');
+
+    model.value.value = 1;
+    deliverChangeRecords();
+    expect(lastValue, null);
+
+    // Stop observing
+    sub.cancel();
+
+    model.value.value = new TestModel(const Symbol('c'),
+        'hello, back again -- but not observing');
+    deliverChangeRecords();
+    expect(lastValue, null);
+
+    // Resume observing
+    sub = path.values.listen((v) { lastValue = v; });
+
+    model.value.value.value = 'hello. Back for reals';
+    deliverChangeRecords();
+    expect(lastValue, 'hello. Back for reals');
+  });
+
+  test('observe map', () {
+    var model = toSymbolMap({'a': 1});
+    var path = observePath(model, 'a');
+
+    var values = [path.value];
+    var sub = path.values.listen((v) { values.add(v); });
+    expect(values, [1]);
+
+    model[sym('a')] = 2;
+    deliverChangeRecords();
+    expect(values, [1, 2]);
+
+    sub.cancel();
+    model[sym('a')] = 3;
+    deliverChangeRecords();
+    expect(values, [1, 2]);
+  });
+}
+
+class TestModel extends ObservableBase {
+  final Symbol fieldName;
+  var _value;
+
+  TestModel(this.fieldName, [initialValue]) : _value = initialValue;
+
+  get value => _value;
+
+  void set value(newValue) {
+    _value = notifyPropertyChange(fieldName, _value, newValue);
+  }
+
+  getValueWorkaround(key) {
+    if (key == fieldName) return value;
+    return null;
+  }
+  void setValueWorkaround(key, newValue) {
+    if (key == fieldName) value = newValue;
+  }
+
+  toString() => '#<$runtimeType $fieldName: $_value>';
+}
+
+_record(key, oldValue, newValue, [kind = ChangeRecord.FIELD]) =>
+    new ChangeRecord(key, oldValue, newValue, kind: kind);
diff --git a/tests/language/reflect_core_vm_test.dart b/tests/language/reflect_core_vm_test.dart
new file mode 100644
index 0000000..d6e52f1
--- /dev/null
+++ b/tests/language/reflect_core_vm_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test reflection of private functions in core classes.
+
+import "package:expect/expect.dart";
+import "dart:mirrors";
+
+main() {
+  var s = "string";
+  var im = reflect(s);
+  try {
+    im.invoke(const Symbol("_setAt"), [0, 65]);
+    Expect.isTrue(false);  // Unreachable.
+  } catch (e) {
+    Expect.equals(true, e is NoSuchMethodError);
+  }
+}
+
diff --git a/tools/VERSION b/tools/VERSION
index 876e2f8..6f49db1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -23,9 +23,9 @@
 #  * Making cherry-picks to stable channel
 #     - increase PATCH by 1
 #
-CHANNEL be
+CHANNEL dev
 MAJOR 1
 MINOR 8
 PATCH 0
-PRERELEASE 0
+PRERELEASE 2
 PRERELEASE_PATCH 0
diff --git a/tools/dartium/download_shellscript_template.bat b/tools/dartium/download_shellscript_template.bat
index bf81832..d41951d 100644
--- a/tools/dartium/download_shellscript_template.bat
+++ b/tools/dartium/download_shellscript_template.bat
@@ -1,16 +1,16 @@
-@REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-@REM for details. All rights reserved. Use of this source code is governed by a
-@REM BSD-style license that can be found in the LICENSE file.
-
-@REM This script will download VAR_DOWNLOAD_URL to VAR_DESTINATION in the
-@REM current working directory.
-
-@echo off
-
-set "CHROMIUM_DIR=%~dp0"
-set "SDK_BIN=%CHROMIUM_DIR%\..\dart-sdk\bin"
-
-set "DART=%SDK_BIN%\dart.exe"
-set "DOWNLOAD_SCRIPT=%CHROMIUM_DIR%\download_file.dart"
-
-"%DART%" "%DOWNLOAD_SCRIPT%" "VAR_DOWNLOAD_URL" "VAR_DESTINATION"
+@REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file

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

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

+

+@REM This script will download VAR_DOWNLOAD_URL to VAR_DESTINATION in the

+@REM current working directory.

+

+@echo off

+

+set "CHROMIUM_DIR=%~dp0"

+set "SDK_BIN=%CHROMIUM_DIR%\..\dart-sdk\bin"

+

+set "DART=%SDK_BIN%\dart.exe"

+set "DOWNLOAD_SCRIPT=%CHROMIUM_DIR%\download_file.dart"

+

+"%DART%" "%DOWNLOAD_SCRIPT%" "VAR_DOWNLOAD_URL" "VAR_DESTINATION"

diff --git a/tools/dom/src/PathObserver.dart b/tools/dom/src/PathObserver.dart
new file mode 100644
index 0000000..bc07ac1
--- /dev/null
+++ b/tools/dom/src/PathObserver.dart
@@ -0,0 +1,288 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html;
+
+// This code is inspired by ChangeSummary:
+// https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
+// ...which underlies MDV. Since we don't need the functionality of
+// ChangeSummary, we just implement what we need for data bindings.
+// This allows our implementation to be much simpler.
+
+// TODO(jmesserly): should we make these types stronger, and require
+// Observable objects? Currently, it is fine to say something like:
+//     var path = new PathObserver(123, '');
+//     print(path.value); // "123"
+//
+// Furthermore this degenerate case is allowed:
+//     var path = new PathObserver(123, 'foo.bar.baz.qux');
+//     print(path.value); // "null"
+//
+// Here we see that any invalid (i.e. not Observable) value will break the
+// path chain without producing an error or exception.
+//
+// Now the real question: should we do this? For the former case, the behavior
+// is correct but we could chose to handle it in the dart:html bindings layer.
+// For the latter case, it might be better to throw an error so users can find
+// the problem.
+
+
+/**
+ * A data-bound path starting from a view-model or model object, for example
+ * `foo.bar.baz`.
+ *
+ * When the [values] stream is being listened to, this will observe changes to
+ * the object and any intermediate object along the path, and send [values]
+ * accordingly. When all listeners are unregistered it will stop observing
+ * the objects.
+ *
+ * This class is used to implement [Node.bind] and similar functionality.
+ */
+// TODO(jmesserly): find a better home for this type.
+@Experimental
+class PathObserver {
+  /** The object being observed. */
+  final object;
+
+  /** The path string. */
+  final String path;
+
+  /** True if the path is valid, otherwise false. */
+  final bool _isValid;
+
+  // TODO(jmesserly): same issue here as ObservableMixin: is there an easier
+  // way to get a broadcast stream?
+  StreamController _values;
+  Stream _valueStream;
+
+  _PropertyObserver _observer, _lastObserver;
+
+  Object _lastValue;
+  bool _scheduled = false;
+
+  /**
+   * Observes [path] on [object] for changes. This returns an object that can be
+   * used to get the changes and get/set the value at this path.
+   * See [PathObserver.values] and [PathObserver.value].
+   */
+  PathObserver(this.object, String path)
+    : path = path, _isValid = _isPathValid(path) {
+
+    // TODO(jmesserly): if the path is empty, or the object is! Observable, we
+    // can optimize the PathObserver to be more lightweight.
+
+    _values = new StreamController.broadcast(sync: true,
+                                             onListen: _observe,
+                                             onCancel: _unobserve);
+
+    if (_isValid) {
+      var segments = [];
+      for (var segment in path.trim().split('.')) {
+        if (segment == '') continue;
+        var index = int.parse(segment, onError: (_) {});
+        segments.add(index != null ? index : new Symbol(segment));
+      }
+
+      // Create the property observer linked list.
+      // Note that the structure of a path can't change after it is initially
+      // constructed, even though the objects along the path can change.
+      for (int i = segments.length - 1; i >= 0; i--) {
+        _observer = new _PropertyObserver(this, segments[i], _observer);
+        if (_lastObserver == null) _lastObserver = _observer;
+      }
+    }
+  }
+
+  // TODO(jmesserly): we could try adding the first value to the stream, but
+  // that delivers the first record async.
+  /**
+   * Listens to the stream, and invokes the [callback] immediately with the
+   * current [value]. This is useful for bindings, which want to be up-to-date
+   * immediately.
+   */
+  StreamSubscription bindSync(void callback(value)) {
+    var result = values.listen(callback);
+    callback(value);
+    return result;
+  }
+
+  // TODO(jmesserly): should this be a change record with the old value?
+  // TODO(jmesserly): should this be a broadcast stream? We only need
+  // single-subscription in the bindings system, so single sub saves overhead.
+  /**
+   * Gets the stream of values that were observed at this path.
+   * This returns a single-subscription stream.
+   */
+  Stream get values => _values.stream;
+
+  /** Force synchronous delivery of [values]. */
+  void _deliverValues() {
+    _scheduled = false;
+
+    var newValue = value;
+    if (!identical(_lastValue, newValue)) {
+      _values.add(newValue);
+      _lastValue = newValue;
+    }
+  }
+
+  void _observe() {
+    if (_observer != null) {
+      _lastValue = value;
+      _observer.observe();
+    }
+  }
+
+  void _unobserve() {
+    if (_observer != null) _observer.unobserve();
+  }
+
+  void _notifyChange() {
+    if (_scheduled) return;
+    _scheduled = true;
+
+    // TODO(jmesserly): should we have a guarenteed order with respect to other
+    // paths? If so, we could implement this fairly easily by sorting instances
+    // of this class by birth order before delivery.
+    queueChangeRecords(_deliverValues);
+  }
+
+  /** Gets the last reported value at this path. */
+  get value {
+    if (!_isValid) return null;
+    if (_observer == null) return object;
+    _observer.ensureValue(object);
+    return _lastObserver.value;
+  }
+
+  /** Sets the value at this path. */
+  void set value(Object value) {
+    // TODO(jmesserly): throw if property cannot be set?
+    // MDV seems tolerant of these error.
+    if (_observer == null || !_isValid) return;
+    _observer.ensureValue(object);
+    var last = _lastObserver;
+    if (_setObjectProperty(last._object, last._property, value)) {
+      // Technically, this would get updated asynchronously via a change record.
+      // However, it is nice if calling the getter will yield the same value
+      // that was just set. So we use this opportunity to update our cache.
+      last.value = value;
+    }
+  }
+}
+
+// TODO(jmesserly): these should go away in favor of mirrors!
+_getObjectProperty(object, property) {
+  if (object is List && property is int) {
+    if (property >= 0 && property < object.length) {
+      return object[property];
+    } else {
+      return null;
+    }
+  }
+
+  // TODO(jmesserly): what about length?
+  if (object is Map) return object[property];
+
+  if (object is Observable) return object.getValueWorkaround(property);
+
+  return null;
+}
+
+bool _setObjectProperty(object, property, value) {
+  if (object is List && property is int) {
+    object[property] = value;
+  } else if (object is Map) {
+    object[property] = value;
+  } else if (object is Observable) {
+    (object as Observable).setValueWorkaround(property, value);
+  } else {
+    return false;
+  }
+  return true;
+}
+
+
+class _PropertyObserver {
+  final PathObserver _path;
+  final _property;
+  final _PropertyObserver _next;
+
+  // TODO(jmesserly): would be nice not to store both of these.
+  Object _object;
+  Object _value;
+  StreamSubscription _sub;
+
+  _PropertyObserver(this._path, this._property, this._next);
+
+  get value => _value;
+
+  void set value(Object newValue) {
+    _value = newValue;
+    if (_next != null) {
+      if (_sub != null) _next.unobserve();
+      _next.ensureValue(_value);
+      if (_sub != null) _next.observe();
+    }
+  }
+
+  void ensureValue(object) {
+    // If we're observing, values should be up to date already.
+    if (_sub != null) return;
+
+    _object = object;
+    value = _getObjectProperty(object, _property);
+  }
+
+  void observe() {
+    if (_object is Observable) {
+      assert(_sub == null);
+      _sub = (_object as Observable).changes.listen(_onChange);
+    }
+    if (_next != null) _next.observe();
+  }
+
+  void unobserve() {
+    if (_sub == null) return;
+
+    _sub.cancel();
+    _sub = null;
+    if (_next != null) _next.unobserve();
+  }
+
+  void _onChange(List<ChangeRecord> changes) {
+    for (var change in changes) {
+      // TODO(jmesserly): what to do about "new Symbol" here?
+      // Ideally this would only preserve names if the user has opted in to
+      // them being preserved.
+      // TODO(jmesserly): should we drop observable maps with String keys?
+      // If so then we only need one check here.
+      if (change.changes(_property)) {
+        value = _getObjectProperty(_object, _property);
+        _path._notifyChange();
+        return;
+      }
+    }
+  }
+}
+
+// From: https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
+
+const _pathIndentPart = r'[$a-z0-9_]+[$a-z0-9_\d]*';
+final _pathRegExp = new RegExp('^'
+    '(?:#?' + _pathIndentPart + ')?'
+    '(?:'
+      '(?:\\.' + _pathIndentPart + ')'
+    ')*'
+    r'$', caseSensitive: false);
+
+final _spacesRegExp = new RegExp(r'\s');
+
+bool _isPathValid(String s) {
+  s = s.replaceAll(_spacesRegExp, '');
+
+  if (s == '') return true;
+  if (s[0] == '.') return false;
+  return _pathRegExp.hasMatch(s);
+}
diff --git a/utils/pub/pub.Makefile b/utils/pub/pub.Makefile
new file mode 100644
index 0000000..c1d628d
--- /dev/null
+++ b/utils/pub/pub.Makefile
@@ -0,0 +1,6 @@
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= dart/utils/pub/out
+.PHONY: all
+all:
+	$(MAKE) -C ../.. pub
diff --git a/utils/pub/pub.target.mk b/utils/pub/pub.target.mk
new file mode 100644
index 0000000..6362e21
--- /dev/null
+++ b/utils/pub/pub.target.mk
@@ -0,0 +1,38 @@
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := pub
+### Rules for action "generate_pub_snapshot":
+quiet_cmd_dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot = ACTION dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot $@
+cmd_dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot = LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; cd utils/pub; mkdir -p $(obj)/gen; "$(builddir)/dart" "--package-root=$(builddir)/packages/" "--generate-script-snapshot=$(obj)/gen/pub.dart.snapshot" ../../sdk/lib/_internal/pub/bin/pub.dart
+
+$(obj)/gen/pub.dart.snapshot: obj := $(abs_obj)
+$(obj)/gen/pub.dart.snapshot: builddir := $(abs_builddir)
+$(obj)/gen/pub.dart.snapshot: TOOLSET := $(TOOLSET)
+$(obj)/gen/pub.dart.snapshot: $(builddir)/dart sdk/lib/_internal/pub/bin/pub.dart sdk/lib/_internal/pub/lib/src/http.dart sdk/lib/_internal/pub/lib/src/utils.dart sdk/lib/_internal/pub/lib/src/command_deploy.dart sdk/lib/_internal/pub/lib/src/git_source.dart sdk/lib/_internal/pub/lib/src/command_install.dart sdk/lib/_internal/pub/lib/src/exit_codes.dart sdk/lib/_internal/pub/lib/src/command.dart sdk/lib/_internal/pub/lib/src/source_registry.dart sdk/lib/_internal/pub/lib/src/pubspec.dart sdk/lib/_internal/pub/lib/src/command_help.dart sdk/lib/_internal/pub/lib/src/oauth2.dart sdk/lib/_internal/pub/lib/src/command_uploader.dart sdk/lib/_internal/pub/lib/src/error_group.dart sdk/lib/_internal/pub/lib/src/directory_tree.dart sdk/lib/_internal/pub/lib/src/sdk.dart sdk/lib/_internal/pub/lib/src/dart.dart sdk/lib/_internal/pub/lib/src/hosted_source.dart sdk/lib/_internal/pub/lib/src/version.dart sdk/lib/_internal/pub/lib/src/git.dart sdk/lib/_internal/pub/lib/src/io.dart sdk/lib/_internal/pub/lib/src/system_cache.dart sdk/lib/_internal/pub/lib/src/safe_http_server.dart sdk/lib/_internal/pub/lib/src/command_update.dart sdk/lib/_internal/pub/lib/src/command_version.dart sdk/lib/_internal/pub/lib/src/validator.dart sdk/lib/_internal/pub/lib/src/command_cache.dart sdk/lib/_internal/pub/lib/src/source.dart sdk/lib/_internal/pub/lib/src/command_lish.dart sdk/lib/_internal/pub/lib/src/package.dart sdk/lib/_internal/pub/lib/src/log.dart sdk/lib/_internal/pub/lib/src/entrypoint.dart sdk/lib/_internal/pub/lib/src/lock_file.dart sdk/lib/_internal/pub/lib/src/path_source.dart sdk/lib/_internal/pub/lib/src/validator/name.dart sdk/lib/_internal/pub/lib/src/validator/size.dart sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart sdk/lib/_internal/pub/lib/src/validator/directory.dart sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart sdk/lib/_internal/pub/lib/src/validator/dependency.dart sdk/lib/_internal/pub/lib/src/validator/license.dart sdk/lib/_internal/pub/lib/src/validator/lib.dart sdk/lib/_internal/pub/lib/src/solver/version_solver.dart sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart sdk/lib/_internal/pub/test/command_line_config.dart sdk/lib/_internal/pub/test/version_test.dart sdk/lib/_internal/pub/test/io_test.dart sdk/lib/_internal/pub/test/pub_cache_test.dart sdk/lib/_internal/pub/test/test_pub.dart sdk/lib/_internal/pub/test/lock_file_test.dart sdk/lib/_internal/pub/test/real_version_test.dart sdk/lib/_internal/pub/test/utils_test.dart sdk/lib/_internal/pub/test/directory_tree_test.dart sdk/lib/_internal/pub/test/unknown_source_test.dart sdk/lib/_internal/pub/test/dev_dependency_test.dart sdk/lib/_internal/pub/test/package_files_test.dart sdk/lib/_internal/pub/test/pubspec_test.dart sdk/lib/_internal/pub/test/pub_test.dart sdk/lib/_internal/pub/test/pub_install_and_update_test.dart sdk/lib/_internal/pub/test/version_solver_test.dart sdk/lib/_internal/pub/test/descriptor.dart sdk/lib/_internal/pub/test/error_group_test.dart sdk/lib/_internal/pub/test/pub_uploader_test.dart sdk/lib/_internal/pub/test/lish/cloud_storage_upload_doesnt_redirect_test.dart sdk/lib/_internal/pub/test/lish/cloud_storage_upload_provides_an_error_test.dart sdk/lib/_internal/pub/test/lish/upload_form_provides_an_error_test.dart sdk/lib/_internal/pub/test/lish/utils.dart sdk/lib/_internal/pub/test/lish/package_creation_provides_a_malformed_error_test.dart sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart sdk/lib/_internal/pub/test/lish/upload_form_fields_is_not_a_map_test.dart sdk/lib/_internal/pub/test/lish/package_creation_provides_invalid_json_test.dart sdk/lib/_internal/pub/test/lish/package_creation_provides_a_malformed_success_test.dart sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart sdk/lib/_internal/pub/test/lish/upload_form_is_missing_url_test.dart sdk/lib/_internal/pub/test/lish/force_does_not_publish_if_there_are_errors_test.dart sdk/lib/_internal/pub/test/lish/upload_form_is_missing_fields_test.dart sdk/lib/_internal/pub/test/lish/package_validation_has_an_error_test.dart sdk/lib/_internal/pub/test/lish/preview_package_validation_has_a_warning_test.dart sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_continues_test.dart sdk/lib/_internal/pub/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart sdk/lib/_internal/pub/test/lish/preview_package_validation_has_no_warnings_test.dart sdk/lib/_internal/pub/test/lish/archives_and_uploads_a_package_test.dart sdk/lib/_internal/pub/test/lish/upload_form_url_is_not_a_string_test.dart sdk/lib/_internal/pub/test/lish/force_publishes_if_there_are_warnings_test.dart sdk/lib/_internal/pub/test/lish/upload_form_fields_has_a_non_string_value_test.dart sdk/lib/_internal/pub/test/lish/upload_form_provides_invalid_json_test.dart sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart sdk/lib/_internal/pub/test/update/git/update_locked_test.dart sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart sdk/lib/_internal/pub/test/validator/license_test.dart sdk/lib/_internal/pub/test/validator/utils.dart sdk/lib/_internal/pub/test/validator/pubspec_field_test.dart sdk/lib/_internal/pub/test/validator/dependency_test.dart sdk/lib/_internal/pub/test/validator/directory_test.dart sdk/lib/_internal/pub/test/validator/name_test.dart sdk/lib/_internal/pub/test/validator/lib_test.dart sdk/lib/_internal/pub/test/validator/size_test.dart sdk/lib/_internal/pub/test/validator/utf8_readme_test.dart sdk/lib/_internal/pub/test/validator/compiled_dartdoc_test.dart sdk/lib/_internal/pub/test/oauth2/utils.dart sdk/lib/_internal/pub/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart sdk/lib/_internal/pub/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart sdk/lib/_internal/pub/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart sdk/lib/_internal/pub/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart sdk/lib/_internal/pub/test/descriptor/tar.dart sdk/lib/_internal/pub/test/descriptor/git.dart sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart sdk/lib/_internal/pub/test/hosted/offline_test.dart sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart sdk/lib/_internal/pub/test/hosted/remove_removed_transitive_dependency_test.dart sdk/lib/_internal/pub/test/hosted/remove_removed_dependency_test.dart sdk/lib/_internal/pub/test/install/relative_symlink_test.dart sdk/lib/_internal/pub/test/install/broken_symlink_test.dart sdk/lib/_internal/pub/test/install/switch_source_test.dart sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart sdk/lib/_internal/pub/test/install/git/check_out_test.dart sdk/lib/_internal/pub/test/install/git/lock_version_test.dart sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart sdk/lib/_internal/pub/test/install/hosted/install_test.dart sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart sdk/lib/_internal/pub/test/install/path/shared_dependency_test.dart sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart sdk/lib/_internal/pub/test/install/path/relative_path_test.dart sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart sdk/lib/_internal/pub/test/deploy/copies_non_dart_files_to_deploy_test.dart sdk/lib/_internal/pub/test/deploy/ignores_non_entrypoint_dart_files_test.dart sdk/lib/_internal/pub/test/deploy/compiles_dart_entrypoints_to_dart_and_js_test.dart sdk/lib/_internal/pub/test/deploy/reports_dart_parse_errors_test.dart sdk/lib/_internal/pub/test/deploy/copies_dart_js_next_to_entrypoints_test.dart sdk/lib/_internal/pub/test/deploy/with_no_web_directory_test.dart sdk/lib/_internal/libraries.dart sdk/lib/_internal/compiler/compiler.dart sdk/lib/_internal/compiler/implementation/dart_types.dart sdk/lib/_internal/compiler/implementation/string_validator.dart sdk/lib/_internal/compiler/implementation/world.dart sdk/lib/_internal/compiler/implementation/typechecker.dart sdk/lib/_internal/compiler/implementation/filenames.dart sdk/lib/_internal/compiler/implementation/dart2js.dart sdk/lib/_internal/compiler/implementation/patch_parser.dart sdk/lib/_internal/compiler/implementation/constants.dart sdk/lib/_internal/compiler/implementation/script.dart sdk/lib/_internal/compiler/implementation/library_loader.dart sdk/lib/_internal/compiler/implementation/enqueue.dart sdk/lib/_internal/compiler/implementation/compiler.dart sdk/lib/_internal/compiler/implementation/diagnostic_listener.dart sdk/lib/_internal/compiler/implementation/warnings.dart sdk/lib/_internal/compiler/implementation/source_file_provider.dart sdk/lib/_internal/compiler/implementation/tree_validator.dart sdk/lib/_internal/compiler/implementation/apiimpl.dart sdk/lib/_internal/compiler/implementation/native_handler.dart sdk/lib/_internal/compiler/implementation/constant_system_dart.dart sdk/lib/_internal/compiler/implementation/dart2jslib.dart sdk/lib/_internal/compiler/implementation/compile_time_constants.dart sdk/lib/_internal/compiler/implementation/closure.dart sdk/lib/_internal/compiler/implementation/code_buffer.dart sdk/lib/_internal/compiler/implementation/source_file.dart sdk/lib/_internal/compiler/implementation/deferred_load.dart sdk/lib/_internal/compiler/implementation/resolved_visitor.dart sdk/lib/_internal/compiler/implementation/colors.dart sdk/lib/_internal/compiler/implementation/source_map_builder.dart sdk/lib/_internal/compiler/implementation/constant_system.dart sdk/lib/_internal/compiler/implementation/util/characters.dart sdk/lib/_internal/compiler/implementation/util/util.dart sdk/lib/_internal/compiler/implementation/util/uri_extras.dart sdk/lib/_internal/compiler/implementation/util/link_implementation.dart sdk/lib/_internal/compiler/implementation/util/link.dart sdk/lib/_internal/compiler/implementation/util/util_implementation.dart sdk/lib/_internal/compiler/implementation/tools/mini_parser.dart sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart sdk/lib/_internal/compiler/implementation/dart_backend/dart_backend.dart sdk/lib/_internal/compiler/implementation/dart_backend/emitter.dart sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart sdk/lib/_internal/compiler/implementation/js_backend/namer.dart sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart sdk/lib/_internal/compiler/implementation/js_backend/backend.dart sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart sdk/lib/_internal/compiler/implementation/lib/string_helper.dart sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart sdk/lib/_internal/compiler/implementation/lib/js_rti.dart sdk/lib/_internal/compiler/implementation/lib/core_patch.dart sdk/lib/_internal/compiler/implementation/lib/js_array.dart sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart sdk/lib/_internal/compiler/implementation/lib/async_patch.dart sdk/lib/_internal/compiler/implementation/lib/collection_dev_patch.dart sdk/lib/_internal/compiler/implementation/lib/js_helper.dart sdk/lib/_internal/compiler/implementation/lib/scalarlist_patch.dart sdk/lib/_internal/compiler/implementation/lib/native_helper.dart sdk/lib/_internal/compiler/implementation/lib/io_patch.dart sdk/lib/_internal/compiler/implementation/lib/js_number.dart sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart sdk/lib/_internal/compiler/implementation/lib/constant_map.dart sdk/lib/_internal/compiler/implementation/lib/typed_data_patch.dart sdk/lib/_internal/compiler/implementation/lib/math_patch.dart sdk/lib/_internal/compiler/implementation/lib/js_string.dart sdk/lib/_internal/compiler/implementation/lib/json_patch.dart sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart sdk/lib/_internal/compiler/implementation/lib/interceptors.dart sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart sdk/lib/_internal/compiler/implementation/mirrors/util.dart sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart sdk/lib/_internal/compiler/implementation/resolution/scope.dart sdk/lib/_internal/compiler/implementation/resolution/resolution.dart sdk/lib/_internal/compiler/implementation/resolution/secret_tree_element.dart sdk/lib/_internal/compiler/implementation/resolution/members.dart sdk/lib/_internal/compiler/implementation/ssa/ssa.dart sdk/lib/_internal/compiler/implementation/ssa/bailout.dart sdk/lib/_internal/compiler/implementation/ssa/codegen.dart sdk/lib/_internal/compiler/implementation/ssa/types.dart sdk/lib/_internal/compiler/implementation/ssa/validate.dart sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart sdk/lib/_internal/compiler/implementation/ssa/optimize.dart sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart sdk/lib/_internal/compiler/implementation/ssa/nodes.dart sdk/lib/_internal/compiler/implementation/ssa/value_set.dart sdk/lib/_internal/compiler/implementation/ssa/builder.dart sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart sdk/lib/_internal/compiler/implementation/ssa/tracer.dart sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart sdk/lib/_internal/compiler/implementation/js/precedence.dart sdk/lib/_internal/compiler/implementation/js/nodes.dart sdk/lib/_internal/compiler/implementation/js/builder.dart sdk/lib/_internal/compiler/implementation/js/printer.dart sdk/lib/_internal/compiler/implementation/js/js.dart sdk/lib/_internal/compiler/implementation/types/types.dart sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart sdk/lib/_internal/compiler/implementation/types/type_mask.dart sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart sdk/lib/_internal/compiler/implementation/elements/elements.dart sdk/lib/_internal/compiler/implementation/elements/modelx.dart sdk/lib/_internal/compiler/implementation/universe/side_effects.dart sdk/lib/_internal/compiler/implementation/universe/selector_map.dart sdk/lib/_internal/compiler/implementation/universe/universe.dart sdk/lib/_internal/compiler/implementation/universe/function_set.dart sdk/lib/_internal/compiler/implementation/scanner/byte_array_scanner.dart sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart sdk/lib/_internal/compiler/implementation/scanner/scanner_implementation.dart sdk/lib/_internal/compiler/implementation/scanner/listener.dart sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart sdk/lib/_internal/compiler/implementation/scanner/parser_task.dart sdk/lib/_internal/compiler/implementation/scanner/scanner.dart sdk/lib/_internal/compiler/implementation/scanner/keyword.dart sdk/lib/_internal/compiler/implementation/scanner/scanner_task.dart sdk/lib/_internal/compiler/implementation/scanner/partial_parser.dart sdk/lib/_internal/compiler/implementation/scanner/token.dart sdk/lib/_internal/compiler/implementation/scanner/parser.dart sdk/lib/_internal/compiler/implementation/scanner/array_based_scanner.dart sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart sdk/lib/_internal/compiler/implementation/tree/visitors.dart sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart sdk/lib/_internal/compiler/implementation/tree/unparser.dart sdk/lib/_internal/compiler/implementation/tree/tree.dart sdk/lib/_internal/compiler/implementation/tree/nodes.dart sdk/lib/_internal/compiler/implementation/tree/dartstring.dart sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart sdk/lib/_internal/compiler/samples/leap/leap_leg.dart sdk/lib/_internal/compiler/samples/leap/request_cache.dart sdk/lib/_internal/compiler/samples/leap/leap_script.dart sdk/lib/_internal/compiler/samples/leap/leap_server.dart sdk/lib/_internal/compiler/samples/leap/leap.dart sdk/lib/_internal/compiler/samples/darttags/darttags.dart pkg/intl/lib/number_symbols.dart pkg/intl/lib/intl.dart pkg/intl/lib/number_format.dart pkg/intl/lib/date_format.dart pkg/intl/lib/number_symbols_data.dart pkg/intl/lib/date_symbol_data_http_request.dart pkg/intl/lib/intl_browser.dart pkg/intl/lib/bidi_utils.dart pkg/intl/lib/date_symbol_data_local.dart pkg/intl/lib/date_time_patterns.dart pkg/intl/lib/message_lookup_by_library.dart pkg/intl/lib/date_symbol_data_file.dart pkg/intl/lib/extract_messages.dart pkg/intl/lib/generate_localized.dart pkg/intl/lib/bidi_formatter.dart pkg/intl/lib/date_symbols.dart pkg/intl/lib/intl_standalone.dart pkg/intl/lib/src/date_format_helpers.dart pkg/intl/lib/src/http_request_data_reader.dart pkg/intl/lib/src/file_data_reader.dart pkg/intl/lib/src/date_format_internal.dart pkg/intl/lib/src/intl_message.dart pkg/intl/lib/src/intl_helpers.dart pkg/intl/lib/src/date_format_field.dart pkg/intl/lib/src/lazy_locale_data.dart pkg/intl/lib/src/data/dates/localeList.dart pkg/intl/test/date_time_format_local_odd_test.dart pkg/intl/test/data_directory.dart pkg/intl/test/date_time_format_local_even_test.dart pkg/intl/test/intl_message_basic_example_test.dart pkg/intl/test/number_test_data.dart pkg/intl/test/bidi_utils_test.dart pkg/intl/test/date_time_format_test_data.dart pkg/intl/test/number_closure_test.dart pkg/intl/test/date_time_format_file_even_test.dart pkg/intl/test/number_format_test.dart pkg/intl/test/intl_test.dart pkg/intl/test/find_default_locale_standalone_test.dart pkg/intl/test/date_time_format_test_core.dart pkg/intl/test/date_time_format_http_request_test.dart pkg/intl/test/date_time_format_uninitialized_test.dart pkg/intl/test/date_time_format_test_stub.dart pkg/intl/test/find_default_locale_browser_test.dart pkg/intl/test/bidi_format_test.dart pkg/intl/test/date_time_format_file_odd_test.dart pkg/intl/test/message_extraction/generate_from_json.dart pkg/intl/test/message_extraction/sample_with_messages.dart pkg/intl/test/message_extraction/make_hardcoded_translation.dart pkg/intl/test/message_extraction/part_of_sample_with_messages.dart pkg/intl/test/message_extraction/extract_to_json.dart pkg/intl/test/message_extraction/message_extraction_test.dart pkg/intl/tool/generate_locale_data_files.dart pkg/intl/example/basic/basic_example_runner.dart pkg/intl/example/basic/basic_example.dart pkg/intl/example/basic/messages_de.dart pkg/intl/example/basic/messages_all.dart pkg/intl/example/basic/messages_th_th.dart pkg/serialization/lib/serialization.dart pkg/serialization/lib/src/format.dart pkg/serialization/lib/src/serialization_rule.dart pkg/serialization/lib/src/serialization_helpers.dart pkg/serialization/lib/src/mirrors_helpers.dart pkg/serialization/lib/src/basic_rule.dart pkg/serialization/lib/src/reader_writer.dart pkg/serialization/test/serialization_test.dart pkg/serialization/test/test_models.dart pkg/serialization/test/polyfill_identity_map_test.dart pkg/serialization/test/no_library_test.dart pkg/analyzer_experimental/bin/analyzer.dart pkg/analyzer_experimental/lib/options.dart pkg/analyzer_experimental/lib/analyzer.dart pkg/analyzer_experimental/lib/src/utils.dart pkg/analyzer_experimental/lib/src/error_formatter.dart pkg/analyzer_experimental/lib/src/analyzer_impl.dart pkg/analyzer_experimental/lib/src/error.dart pkg/analyzer_experimental/lib/src/generated/constant.dart pkg/analyzer_experimental/lib/src/generated/utilities_dart.dart pkg/analyzer_experimental/lib/src/generated/instrumentation.dart pkg/analyzer_experimental/lib/src/generated/source_io.dart pkg/analyzer_experimental/lib/src/generated/ast.dart pkg/analyzer_experimental/lib/src/generated/sdk.dart pkg/analyzer_experimental/lib/src/generated/element.dart pkg/analyzer_experimental/lib/src/generated/engine.dart pkg/analyzer_experimental/lib/src/generated/scanner.dart pkg/analyzer_experimental/lib/src/generated/java_core.dart pkg/analyzer_experimental/lib/src/generated/java_engine.dart pkg/analyzer_experimental/lib/src/generated/java_io.dart pkg/analyzer_experimental/lib/src/generated/parser.dart pkg/analyzer_experimental/lib/src/generated/java_junit.dart pkg/analyzer_experimental/lib/src/generated/sdk_io.dart pkg/analyzer_experimental/lib/src/generated/html.dart pkg/analyzer_experimental/lib/src/generated/java_engine_io.dart pkg/analyzer_experimental/lib/src/generated/error.dart pkg/analyzer_experimental/lib/src/generated/source.dart pkg/analyzer_experimental/lib/src/generated/resolver.dart pkg/analyzer_experimental/test/utils.dart pkg/analyzer_experimental/test/error_test.dart pkg/analyzer_experimental/test/options_test.dart pkg/analyzer_experimental/test/generated/resolver_test.dart pkg/analyzer_experimental/test/generated/scanner_test.dart pkg/analyzer_experimental/test/generated/element_test.dart pkg/analyzer_experimental/test/generated/ast_test.dart pkg/analyzer_experimental/test/generated/test_support.dart pkg/analyzer_experimental/test/generated/parser_test.dart pkg/analyzer_experimental/example/scanner_driver.dart pkg/analyzer_experimental/example/resolver_driver.dart pkg/analyzer_experimental/example/parser_driver.dart pkg/webdriver/lib/webdriver.dart pkg/webdriver/lib/src/base64decoder.dart pkg/webdriver/test/webdriver_test.dart pkg/fixnum/lib/fixnum.dart pkg/fixnum/lib/src/int64.dart pkg/fixnum/lib/src/intx.dart pkg/fixnum/lib/src/int32.dart pkg/fixnum/test/int_32_test.dart pkg/fixnum/test/int_64_vm_test.dart pkg/fixnum/test/int_64_test.dart pkg/pathos/lib/path.dart pkg/pathos/test/pathos_test.dart pkg/pathos/test/pathos_windows_test.dart pkg/pathos/test/pathos_posix_test.dart pkg/crypto/lib/crypto.dart pkg/crypto/lib/src/crypto_utils.dart pkg/crypto/lib/src/hmac.dart pkg/crypto/lib/src/sha1.dart pkg/crypto/lib/src/hash_utils.dart pkg/crypto/lib/src/md5.dart pkg/crypto/lib/src/sha256.dart pkg/meta/lib/meta.dart pkg/oauth2/lib/oauth2.dart pkg/oauth2/lib/src/utils.dart pkg/oauth2/lib/src/expiration_exception.dart pkg/oauth2/lib/src/credentials.dart pkg/oauth2/lib/src/authorization_exception.dart pkg/oauth2/lib/src/authorization_code_grant.dart pkg/oauth2/lib/src/handle_access_token_response.dart pkg/oauth2/lib/src/client.dart pkg/oauth2/test/utils.dart pkg/oauth2/test/handle_access_token_response_test.dart pkg/oauth2/test/authorization_code_grant_test.dart pkg/oauth2/test/client_test.dart pkg/oauth2/test/utils_test.dart pkg/oauth2/test/credentials_test.dart pkg/http/lib/http.dart pkg/http/lib/testing.dart pkg/http/lib/src/io_client.dart pkg/http/lib/src/utils.dart pkg/http/lib/src/base_request.dart pkg/http/lib/src/streamed_response.dart pkg/http/lib/src/byte_stream.dart pkg/http/lib/src/base_client.dart pkg/http/lib/src/streamed_request.dart pkg/http/lib/src/base_response.dart pkg/http/lib/src/mock_client.dart pkg/http/lib/src/response.dart pkg/http/lib/src/request.dart pkg/http/lib/src/client.dart pkg/http/lib/src/multipart_file.dart pkg/http/lib/src/multipart_request.dart pkg/http/test/mock_client_test.dart pkg/http/test/utils.dart pkg/http/test/streamed_request_test.dart pkg/http/test/multipart_test.dart pkg/http/test/client_test.dart pkg/http/test/http_test.dart pkg/http/test/request_test.dart pkg/http/test/response_test.dart pkg/http/test/safe_http_server.dart pkg/expect/lib/expect.dart pkg/mdv_observe/lib/mdv_observe.dart pkg/mdv_observe/lib/src/observable_list.dart pkg/mdv_observe/lib/src/observable_map.dart pkg/mdv_observe/lib/src/observable_box.dart pkg/mdv_observe/test/utils.dart pkg/mdv_observe/test/list_change_test.dart pkg/mdv_observe/test/observable_list_test.dart pkg/mdv_observe/test/observe_test.dart pkg/mdv_observe/test/observable_map_test.dart pkg/logging/lib/logging.dart pkg/logging/test/logging_test.dart pkg/stack_trace/lib/stack_trace.dart pkg/stack_trace/lib/src/utils.dart pkg/stack_trace/lib/src/lazy_trace.dart pkg/stack_trace/lib/src/trace.dart pkg/stack_trace/lib/src/frame.dart pkg/stack_trace/test/frame_test.dart pkg/stack_trace/test/trace_test.dart pkg/yaml/lib/yaml.dart pkg/yaml/lib/src/composer.dart pkg/yaml/lib/src/utils.dart pkg/yaml/lib/src/yaml_exception.dart pkg/yaml/lib/src/deep_equals.dart pkg/yaml/lib/src/visitor.dart pkg/yaml/lib/src/yaml_map.dart pkg/yaml/lib/src/parser.dart pkg/yaml/lib/src/model.dart pkg/yaml/lib/src/constructor.dart pkg/yaml/test/yaml_test.dart pkg/scheduled_test/lib/scheduled_test.dart pkg/scheduled_test/lib/scheduled_process.dart pkg/scheduled_test/lib/scheduled_server.dart pkg/scheduled_test/lib/descriptor.dart pkg/scheduled_test/lib/src/utils.dart pkg/scheduled_test/lib/src/schedule_error.dart pkg/scheduled_test/lib/src/task.dart pkg/scheduled_test/lib/src/substitute_future.dart pkg/scheduled_test/lib/src/scheduled_future_matchers.dart pkg/scheduled_test/lib/src/value_future.dart pkg/scheduled_test/lib/src/mock_clock.dart pkg/scheduled_test/lib/src/future_group.dart pkg/scheduled_test/lib/src/schedule.dart pkg/scheduled_test/lib/src/scheduled_server/handler.dart pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart pkg/scheduled_test/lib/src/descriptor/async_descriptor.dart pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart pkg/scheduled_test/lib/src/descriptor/descriptor.dart pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart pkg/scheduled_test/test/utils.dart pkg/scheduled_test/test/substitute_future_test.dart pkg/scheduled_test/test/scheduled_server_test.dart pkg/scheduled_test/test/scheduled_future_matchers_test.dart pkg/scheduled_test/test/metatest.dart pkg/scheduled_test/test/value_future_test.dart pkg/scheduled_test/test/scheduled_process_test.dart pkg/scheduled_test/test/descriptor/utils.dart pkg/scheduled_test/test/descriptor/file_test.dart pkg/scheduled_test/test/descriptor/nothing_test.dart pkg/scheduled_test/test/descriptor/pattern_test.dart pkg/scheduled_test/test/descriptor/directory_test.dart pkg/scheduled_test/test/descriptor/async_test.dart pkg/scheduled_test/test/scheduled_test/current_schedule_state_test.dart pkg/scheduled_test/test/scheduled_test/current_schedule_current_task_test.dart pkg/scheduled_test/test/scheduled_test/nested_task_test.dart pkg/scheduled_test/test/scheduled_test/on_exception_test.dart pkg/scheduled_test/test/scheduled_test/task_return_value_test.dart pkg/scheduled_test/test/scheduled_test/abort_test.dart pkg/scheduled_test/test/scheduled_test/timeout_test.dart pkg/scheduled_test/test/scheduled_test/out_of_band_task_test.dart pkg/scheduled_test/test/scheduled_test/wrap_async_test.dart pkg/scheduled_test/test/scheduled_test/wrap_future_test.dart pkg/scheduled_test/test/scheduled_test/signal_error_test.dart pkg/scheduled_test/test/scheduled_test/set_up_test.dart pkg/scheduled_test/test/scheduled_test/on_complete_test.dart pkg/scheduled_test/test/scheduled_test/simple_test.dart pkg/scheduled_test/test/scheduled_test/current_schedule_errors_test.dart pkg/unittest/lib/unittest.dart pkg/unittest/lib/html_individual_config.dart pkg/unittest/lib/vm_config.dart pkg/unittest/lib/html_enhanced_config.dart pkg/unittest/lib/matcher.dart pkg/unittest/lib/interactive_html_config.dart pkg/unittest/lib/mock.dart pkg/unittest/lib/html_config.dart pkg/unittest/lib/compact_vm_config.dart pkg/unittest/lib/src/expect.dart pkg/unittest/lib/src/basematcher.dart pkg/unittest/lib/src/utils.dart pkg/unittest/lib/src/string_matchers.dart pkg/unittest/lib/src/pretty_print.dart pkg/unittest/lib/src/core_matchers.dart pkg/unittest/lib/src/interfaces.dart pkg/unittest/lib/src/description.dart pkg/unittest/lib/src/future_matchers.dart pkg/unittest/lib/src/numeric_matchers.dart pkg/unittest/lib/src/iterable_matchers.dart pkg/unittest/lib/src/map_matchers.dart pkg/unittest/lib/src/config.dart pkg/unittest/lib/src/test_case.dart pkg/unittest/lib/src/operator_matchers.dart pkg/unittest/test/mock_regexp_negative_test.dart pkg/unittest/test/matchers_minified_test.dart pkg/unittest/test/matchers_test.dart pkg/unittest/test/unittest_test.dart pkg/unittest/test/matchers_unminified_test.dart pkg/unittest/test/test_common.dart pkg/unittest/test/test_utils.dart pkg/unittest/test/pretty_print_test.dart pkg/unittest/test/pretty_print_minified_test.dart pkg/unittest/test/instance_test.dart pkg/unittest/test/pretty_print_unminified_test.dart pkg/unittest/test/mock_test.dart pkg/unittest/test/mock_stepwise_negative_test.dart pkg/args/lib/args.dart pkg/args/lib/src/parser.dart pkg/args/lib/src/usage.dart pkg/args/test/args_test.dart pkg/args/test/usage_test.dart pkg/args/test/command_test.dart pkg/args/test/parse_test.dart pkg/args/example/test_runner.dart pkg/source_maps/lib/span.dart pkg/source_maps/lib/source_maps.dart pkg/source_maps/lib/parser.dart pkg/source_maps/lib/builder.dart pkg/source_maps/lib/printer.dart pkg/source_maps/lib/src/utils.dart pkg/source_maps/lib/src/vlq.dart pkg/source_maps/test/vlq_test.dart pkg/source_maps/test/run.dart pkg/source_maps/test/builder_test.dart pkg/source_maps/test/utils_test.dart pkg/source_maps/test/common.dart pkg/source_maps/test/parser_test.dart pkg/source_maps/test/printer_test.dart pkg/source_maps/test/span_test.dart pkg/source_maps/test/end2end_test.dart FORCE_DO_CMD
+	$(call do_cmd,dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot)
+
+all_deps += $(obj)/gen/pub.dart.snapshot
+action_dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot_outputs := $(obj)/gen/pub.dart.snapshot
+
+
+### Rules for final target.
+# Build our special outputs first.
+$(obj).target/utils/pub/pub.stamp: | $(action_dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot_outputs)
+
+# Preserve order dependency of special output on deps.
+$(action_dart_utils_pub_pub_gyp_pub_target_generate_pub_snapshot_outputs): | $(builddir)/dart $(obj).target/pkg/pkg_packages.stamp
+
+$(obj).target/utils/pub/pub.stamp: TOOLSET := $(TOOLSET)
+$(obj).target/utils/pub/pub.stamp: $(builddir)/dart $(obj).target/pkg/pkg_packages.stamp FORCE_DO_CMD
+	$(call do_cmd,touch)
+
+all_deps += $(obj).target/utils/pub/pub.stamp
+# Add target alias
+.PHONY: pub
+pub: $(obj).target/utils/pub/pub.stamp
+
+# Add target alias to "all" target.
+.PHONY: all
+all: pub
+
diff --git a/utils/pub/solver/greedy_solver.dart b/utils/pub/solver/greedy_solver.dart
new file mode 100644
index 0000000..e664ea2
--- /dev/null
+++ b/utils/pub/solver/greedy_solver.dart
@@ -0,0 +1,556 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Attempts to resolve a set of version constraints for a package dependency
+/// graph and select an appropriate set of best specific versions for all
+/// dependent packages. It works iteratively and tries to reach a stable
+/// solution where the constraints of all dependencies are met. If it fails to
+/// reach a solution after a certain number of iterations, it assumes the
+/// dependency graph is unstable and reports and error.
+///
+/// There are two fundamental operations in the process of iterating over the
+/// graph:
+///
+/// 1.  Changing the selected concrete version of some package. (This includes
+///     adding and removing a package too, which is considering changing the
+///     version to or from "none".) In other words, a node has changed.
+/// 2.  Changing the version constraint that one package places on another. In
+///     other words, and edge has changed.
+///
+/// Both of these events have a corresponding (potentional) async operation and
+/// roughly cycle back and forth between each other. When we change the version
+/// of package changes, we asynchronously load the pubspec for the new version.
+/// When that's done, we compare the dependencies of the new version versus the
+/// old one. For everything that differs, we change those constraints between
+/// this package and that dependency.
+///
+/// When a constraint on a package changes, we re-calculate the overall
+/// constraint on that package. I.e. with a shared dependency, we intersect all
+/// of the constraints that its depending packages place on it. If that overall
+/// constraint changes (say from "<3.0.0" to "<2.5.0"), then the currently
+/// picked version for that package may fall outside of the new constraint. If
+/// that happens, we find the new best version that meets the updated constraint
+/// and then the change the package to use that version. That cycles back up to
+/// the beginning again.
+library version_solver1;
+
+import 'dart:async';
+import 'dart:collection' show Queue;
+import 'dart:math' as math;
+
+import '../lock_file.dart';
+import '../log.dart' as log;
+import '../package.dart';
+import '../source.dart';
+import '../source_registry.dart';
+import '../version.dart';
+import 'version_solver.dart';
+
+class GreedyVersionSolver extends VersionSolver {
+  final _packages = <String, DependencyNode>{};
+  final _work = new Queue<WorkItem>();
+  int _numIterations = 0;
+
+  GreedyVersionSolver(SourceRegistry sources, Package root, LockFile lockFile,
+                      List<String> useLatest)
+      : super(sources, root, lockFile, useLatest);
+
+  /// The non-backtracking solver always only tries one solution.
+  int get attemptedSolutions => 1;
+
+  void forceLatestVersion(String package) {
+    // TODO(nweiz): How do we want to detect and handle unknown dependencies
+    // here?
+    getDependency(package).useLatestVersion = true;
+  }
+
+  Future<List<PackageId>> runSolver() {
+    // Kick off the work by adding the root package at its concrete version to
+    // the dependency graph.
+    enqueue(new AddConstraint('(entrypoint)', new PackageRef.root(root)));
+
+    Future processNextWorkItem(_) {
+      while (true) {
+        // Stop if we are done.
+        if (_work.isEmpty) return new Future.value(buildResults());
+
+        // If we appear to be stuck in a loop, then we probably have an unstable
+        // graph, bail. We guess this based on a rough heuristic that it should
+        // only take a certain number of steps to solve a graph with a given
+        // number of connections.
+        // TODO(rnystrom): These numbers here are magic and arbitrary. Tune
+        // when we have a better picture of real-world package topologies.
+        _numIterations++;
+        if (_numIterations > math.max(50, _packages.length * 5)) {
+          throw new CouldNotSolveException();
+        }
+
+        // Run the first work item.
+        var future = _work.removeFirst().process(this);
+
+        // If we have an async operation to perform, chain the loop to resume
+        // when it's done. Otherwise, just loop synchronously.
+        if (future != null) {
+          return future.then(processNextWorkItem);
+        }
+      }
+    }
+
+    return processNextWorkItem(null);
+  }
+
+  void enqueue(WorkItem work) {
+    _work.add(work);
+  }
+
+  DependencyNode getDependency(String package) {
+    // There can be unused dependencies in the graph, so just create an empty
+    // one if needed.
+    _packages.putIfAbsent(package, () => new DependencyNode(package));
+    return _packages[package];
+  }
+
+  /// Sets the best selected version of [package] to [version].
+  void setVersion(String package, Version version) {
+    _packages[package].version = version;
+  }
+
+  /// Returns the most recent version of [dependency] that satisfies all of its
+  /// version constraints.
+  Future<Version> getBestVersion(DependencyNode dependency) {
+    return cache.getVersions(dependency.name,
+        dependency.source, dependency.description).then((versions) {
+      var best = null;
+      for (var ref in versions) {
+        if (dependency.useLatestVersion ||
+            dependency.constraint.allows(ref.version)) {
+          if (best == null || ref.version > best) best = ref.version;
+        }
+      }
+
+      // TODO(rnystrom): Better exception.
+      if (best == null) {
+        if (tryUnlockDepender(dependency)) return null;
+        throw new NoVersionException(dependency.name, dependency.constraint,
+            dependency.toList());
+      } else if (!dependency.constraint.allows(best)) {
+        if (tryUnlockDepender(dependency)) return null;
+        throw new CouldNotUpdateException(
+            dependency.name, dependency.constraint, best);
+      }
+
+      return best;
+    });
+  }
+
+  /// Looks for a package that depends (transitively) on [dependency] and has
+  /// its version locked in the lockfile. If one is found, enqueues an
+  /// [UnlockPackage] work item for it and returns true. Otherwise, returns
+  /// false.
+  ///
+  /// This does a breadth-first search; immediate dependers will be unlocked
+  /// first, followed by transitive dependers.
+  bool tryUnlockDepender(DependencyNode dependency, [Set<String> seen]) {
+    if (seen == null) seen = new Set();
+    // Avoid an infinite loop if there are circular dependencies.
+    if (seen.contains(dependency.name)) return false;
+    seen.add(dependency.name);
+
+    for (var dependerName in dependency.dependers) {
+      var depender = getDependency(dependerName);
+      var locked = lockFile.packages[dependerName];
+      if (locked != null && depender.version == locked.version &&
+          depender.source.name == locked.source.name) {
+        enqueue(new UnlockPackage(depender));
+        return true;
+      }
+    }
+
+    return dependency.dependers.map(getDependency).any((subdependency) =>
+        tryUnlockDepender(subdependency, seen));
+  }
+
+  List<PackageId> buildResults() {
+    return _packages.values
+        .where((dep) => dep.isDependedOn)
+        .map(_dependencyToPackageId)
+        .toList();
+  }
+
+  PackageId _dependencyToPackageId(DependencyNode dep) {
+    var description = dep.description;
+
+    // If the lockfile contains a fully-resolved description for the package,
+    // use that. This allows e.g. Git to ensure that the same commit is used.
+    var lockedPackage = lockFile.packages[dep.name];
+    if (lockedPackage != null && lockedPackage.version == dep.version &&
+        lockedPackage.source.name == dep.source.name &&
+        dep.source.descriptionsEqual(
+            description, lockedPackage.description)) {
+      description = lockedPackage.description;
+    }
+
+    return new PackageId(dep.name, dep.source, dep.version, description);
+  }
+}
+
+/// The constraint solver works by iteratively processing a queue of work items.
+/// Each item is a single atomic change to the dependency graph. Handling them
+/// in a queue lets us handle asynchrony (resolving versions requires
+/// information from servers) as well as avoid deeply nested recursion.
+abstract class WorkItem {
+  /// Processes this work item. Returns a future that completes when the work is
+  /// done. If `null` is returned, that means the work has completed
+  /// synchronously and the next item can be started immediately.
+  Future process(GreedyVersionSolver solver);
+}
+
+/// The best selected version for a package has changed to [version]. If the
+/// previous version of the package is `null`, that means the package is being
+/// added to the graph. If [version] is `null`, it is being removed.
+class ChangeVersion implements WorkItem {
+  /// The name of the package whose version is being changed.
+  final String package;
+
+  /// The source of the package whose version is changing.
+  final Source source;
+
+  /// The description identifying the package whose version is changing.
+  final description;
+
+  /// The new selected version.
+  final Version version;
+
+  ChangeVersion(this.package, this.source, this.description, this.version);
+
+  Future process(GreedyVersionSolver solver) {
+    log.fine("Changing $package to version $version.");
+
+    var dependency = solver.getDependency(package);
+    var oldVersion = dependency.version;
+    solver.setVersion(package, version);
+
+    // The dependencies between the old and new version may be different. Walk
+    // them both and update any constraints that differ between the two.
+    return Future.wait([
+        getDependencyRefs(solver, oldVersion),
+        getDependencyRefs(solver, version)]).then((list) {
+      var oldDependencyRefs = list[0];
+      var newDependencyRefs = list[1];
+
+      for (var oldRef in oldDependencyRefs.values) {
+        if (newDependencyRefs.containsKey(oldRef.name)) {
+          // The dependency is in both versions of this package, but its
+          // constraint may have changed.
+          var newRef = newDependencyRefs.remove(oldRef.name);
+          solver.enqueue(new AddConstraint(package, newRef));
+        } else {
+          // The dependency is not in the new version of the package, so just
+          // remove its constraint.
+          solver.enqueue(new RemoveConstraint(package, oldRef.name));
+        }
+      }
+
+      // Everything that's left is a depdendency that's only in the new
+      // version of the package.
+      for (var newRef in newDependencyRefs.values) {
+        solver.enqueue(new AddConstraint(package, newRef));
+      }
+    });
+  }
+
+  /// Get the dependencies at [version] of the package being changed.
+  Future<Map<String, PackageRef>> getDependencyRefs(VersionSolver solver,
+      Version version) {
+    // If there is no version, it means no package, so no dependencies.
+    if (version == null) {
+      return new Future<Map<String, PackageRef>>.value(<String, PackageRef>{});
+    }
+
+    var id = new PackageId(package, source, version, description);
+    return solver.cache.getPubspec(id).then((pubspec) {
+      var dependencies = <String, PackageRef>{};
+      for (var dependency in pubspec.dependencies) {
+        dependencies[dependency.name] = dependency;
+      }
+
+      // Include dev dependencies only from the root package.
+      if (id.isRoot) {
+        for (var dependency in pubspec.devDependencies) {
+          dependencies[dependency.name] = dependency;
+        }
+      }
+
+      return dependencies;
+    });
+  }
+}
+
+/// A constraint that a depending package places on a dependent package has
+/// changed.
+///
+/// This is an abstract class that contains logic for updating the dependency
+/// graph once a dependency has changed. Changing the dependency is the
+/// responsibility of subclasses.
+abstract class ChangeConstraint implements WorkItem {
+  Future process(GreedyVersionSolver solver);
+
+  void undo(GreedyVersionSolver solver);
+
+  Future _processChange(GreedyVersionSolver solver,
+                        DependencyNode oldDependency,
+                        DependencyNode newDependency) {
+    var name = newDependency.name;
+    var source = oldDependency.source != null ?
+      oldDependency.source : newDependency.source;
+    var description = oldDependency.description != null ?
+      oldDependency.description : newDependency.description;
+    var oldConstraint = oldDependency.constraint;
+    var newConstraint = newDependency.constraint;
+
+    // If the package is over-constrained, i.e. the packages depending have
+    // disjoint constraints, then try unlocking a depender that's locked by the
+    // lockfile. If there are no remaining locked dependencies, throw an error.
+    if (newConstraint != null && newConstraint.isEmpty) {
+      if (solver.tryUnlockDepender(newDependency)) {
+        undo(solver);
+        return null;
+      }
+
+      throw new DisjointConstraintException(name, newDependency.toList());
+    }
+
+    // If this constraint change didn't cause the overall constraint on the
+    // package to change, then we don't need to do any further work.
+    if (oldConstraint == newConstraint) return null;
+
+    // If the dependency has been cut free from the graph, just remove it.
+    if (!newDependency.isDependedOn) {
+      solver.enqueue(new ChangeVersion(name, source, description, null));
+      return null;
+    }
+
+    // If the dependency is on the root package, then we don't need to do
+    // anything since it's already at the best version.
+    if (name == solver.root.name) {
+      solver.enqueue(new ChangeVersion(
+          name, source, description, solver.root.version));
+      return null;
+    }
+
+    // If the dependency is on a package in the lockfile, use the lockfile's
+    // version for that package if it's valid given the other constraints.
+    var lockedPackage = solver.lockFile.packages[name];
+    if (lockedPackage != null && newDependency.source == lockedPackage.source) {
+      var lockedVersion = lockedPackage.version;
+      if (newConstraint.allows(lockedVersion)) {
+        solver.enqueue(
+            new ChangeVersion(name, source, description, lockedVersion));
+        return null;
+      }
+    }
+
+    // The constraint has changed, so see what the best version of the package
+    // that meets the new constraint is.
+    return solver.getBestVersion(newDependency).then((best) {
+      if (best == null) {
+        undo(solver);
+      } else if (newDependency.version != best) {
+        solver.enqueue(new ChangeVersion(name, source, description, best));
+      }
+    });
+  }
+}
+
+/// The constraint given by [ref] is being placed by [depender].
+class AddConstraint extends ChangeConstraint {
+  /// The package that has the dependency.
+  final String depender;
+
+  /// The package being depended on and the constraints being placed on it. The
+  /// source, version, and description in this ref are all considered
+  /// constraints on the dependent package.
+  final PackageRef ref;
+
+  AddConstraint(this.depender, this.ref);
+
+  Future process(GreedyVersionSolver solver) {
+    log.fine("Adding $depender's constraint $ref.");
+
+    var dependency = solver.getDependency(ref.name);
+    var oldDependency = dependency.clone();
+    dependency.placeConstraint(depender, ref);
+    return _processChange(solver, oldDependency, dependency);
+  }
+
+  void undo(GreedyVersionSolver solver) {
+    solver.getDependency(ref.name).removeConstraint(depender);
+  }
+}
+
+/// [depender] is no longer placing a constraint on [dependent].
+class RemoveConstraint extends ChangeConstraint {
+  /// The package that was placing a constraint on [dependent].
+  String depender;
+
+  /// The package that was being depended on.
+  String dependent;
+
+  /// The constraint that was removed.
+  PackageRef _removed;
+
+  RemoveConstraint(this.depender, this.dependent);
+
+  Future process(GreedyVersionSolver solver) {
+    log.fine("Removing $depender's constraint ($_removed) on $dependent.");
+
+    var dependency = solver.getDependency(dependent);
+    var oldDependency = dependency.clone();
+    _removed = dependency.removeConstraint(depender);
+    return _processChange(solver, oldDependency, dependency);
+  }
+
+  void undo(GreedyVersionSolver solver) {
+    solver.getDependency(dependent).placeConstraint(depender, _removed);
+  }
+}
+
+/// [package]'s version is no longer constrained by the lockfile.
+class UnlockPackage implements WorkItem {
+  /// The package being unlocked.
+  DependencyNode package;
+
+  UnlockPackage(this.package);
+
+  Future process(GreedyVersionSolver solver) {
+    log.fine("Unlocking ${package.name}.");
+
+    solver.lockFile.packages.remove(package.name);
+    return solver.getBestVersion(package).then((best) {
+      if (best == null) return null;
+      solver.enqueue(new ChangeVersion(
+          package.name, package.source, package.description, best));
+    });
+  }
+}
+
+/// Describes one [Package] in the [DependencyGraph] and keeps track of which
+/// packages depend on it and what constraints they place on it.
+class DependencyNode {
+  /// The name of the this dependency's package.
+  final String name;
+
+  /// The [PackageRefs] that represent constraints that depending packages have
+  /// placed on this one.
+  final Map<String, PackageRef> _refs;
+
+  /// The currently-selected best version for this dependency.
+  Version version;
+
+  /// Whether this dependency should always select the latest version.
+  bool useLatestVersion = false;
+
+  /// Gets whether or not any other packages are currently depending on this
+  /// one. If `false`, then it means this package is not part of the dependency
+  /// graph and should be omitted.
+  bool get isDependedOn => !_refs.isEmpty;
+
+  /// The names of all the packages that depend on this dependency.
+  Iterable<String> get dependers => _refs.keys;
+
+  /// Gets the overall constraint that all packages are placing on this one.
+  /// If no packages have a constraint on this one (which can happen when this
+  /// package is in the process of being added to the graph), returns `null`.
+  VersionConstraint get constraint {
+    if (_refs.isEmpty) return null;
+    return new VersionConstraint.intersection(
+        _refs.values.map((ref) => ref.constraint));
+  }
+
+  /// The source of this dependency's package.
+  Source get source {
+     var canonical = _canonicalRef();
+     if (canonical == null) return null;
+     return canonical.source;
+  }
+
+  /// The description of this dependency's package.
+  get description {
+     var canonical = _canonicalRef();
+     if (canonical == null) return null;
+     return canonical.description;
+  }
+
+  /// Return the PackageRef that has the canonical source and description for
+  /// this package. If any dependency is on the root package, that will be used;
+  /// otherwise, it will be the source and description that all dependencies
+  /// agree upon.
+  PackageRef _canonicalRef() {
+    if (_refs.isEmpty) return null;
+    var refs = _refs.values;
+    for (var ref in refs) {
+      if (ref.isRoot) return ref;
+    }
+    return refs.first;
+  }
+
+  DependencyNode(this.name)
+      : _refs = <String, PackageRef>{};
+
+  DependencyNode._clone(DependencyNode other)
+      : name = other.name,
+        version = other.version,
+        _refs = new Map<String, PackageRef>.from(other._refs);
+
+  /// Creates a copy of this dependency.
+  DependencyNode clone() => new DependencyNode._clone(this);
+
+  /// Places [ref] as a constraint from [package] onto this.
+  void placeConstraint(String package, PackageRef ref) {
+    var requiredDepender = _requiredDepender();
+    if (requiredDepender != null) {
+      var required = _refs[requiredDepender];
+      if (required.source.name != ref.source.name) {
+        throw new SourceMismatchException(name, [
+            new Dependency(requiredDepender, required),
+            new Dependency(package, ref)]);
+      } else if (!required.descriptionEquals(ref)) {
+        throw new DescriptionMismatchException(name, [
+            new Dependency(requiredDepender, required),
+            new Dependency(package, ref)]);
+      }
+    }
+
+    _refs[package] = ref;
+  }
+
+  /// Returns the name of a package whose constraint source and description
+  /// all other constraints must match. Returns null if there are no
+  /// requirements on new constraints.
+  String _requiredDepender() {
+    if (_refs.isEmpty) return null;
+
+    var dependers = _refs.keys.toList();
+    if (dependers.length == 1) {
+      var depender = dependers[0];
+      if (_refs[depender].isRoot) return null;
+      return depender;
+    }
+
+    return dependers[1];
+  }
+
+  /// Removes the constraint from [package] onto this.
+  PackageRef removeConstraint(String package) => _refs.remove(package);
+
+  /// Converts this to a list of [Dependency] objects like the error types
+  /// expect.
+  List<Dependency> toList() {
+    var result = <Dependency>[];
+    _refs.forEach((name, ref) {
+      result.add(new Dependency(name, ref));
+    });
+    return result;
+  }
+}