| Index: pkg/polymer/lib/src/utils.dart
 | 
| diff --git a/pkg/polymer/lib/src/utils.dart b/pkg/polymer/lib/src/utils.dart
 | 
| index da79dc2478dfff2db0e557b7b6d063a6fa28db3c..59fdc737c31bf698bf1e3eb26de654cf52c9ef2e 100644
 | 
| --- a/pkg/polymer/lib/src/utils.dart
 | 
| +++ b/pkg/polymer/lib/src/utils.dart
 | 
| @@ -1,177 +1,34 @@
 | 
| -// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 | 
| +// 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 polymer.src.utils;
 | 
|  
 | 
| -import 'dart:async';
 | 
| -import 'package:path/path.dart' show Builder;
 | 
| -export 'utils_observe.dart' show toCamelCase, toHyphenedName;
 | 
| -
 | 
| -/**
 | 
| - * An instance of the pathos library builder. We could just use the default
 | 
| - * builder in pathos, but we add this indirection to make it possible to run
 | 
| - * unittest for windows paths.
 | 
| - */
 | 
| -Builder path = new Builder();
 | 
| -
 | 
| -/** Convert a OS specific path into a url. */
 | 
| -String pathToUrl(String relPath) =>
 | 
| -  (path.separator == '/') ? relPath : path.split(relPath).join('/');
 | 
| -
 | 
| -/**
 | 
| - * Invokes [callback], logs how long it took to execute in ms, and returns
 | 
| - * whatever [callback] returns. The log message will be printed if [printTime]
 | 
| - * is true.
 | 
| - */
 | 
| -time(String logMessage, callback(),
 | 
| -     {bool printTime: false, bool useColors: false}) {
 | 
| -  final watch = new Stopwatch();
 | 
| -  watch.start();
 | 
| -  var result = callback();
 | 
| -  watch.stop();
 | 
| -  final duration = watch.elapsedMilliseconds;
 | 
| -  if (printTime) {
 | 
| -    _printMessage(logMessage, duration, useColors);
 | 
| -  }
 | 
| -  return result;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Invokes [callback], logs how long it takes from the moment [callback] is
 | 
| - * executed until the future it returns is completed. Returns the future
 | 
| - * returned by [callback]. The log message will be printed if [printTime]
 | 
| - * is true.
 | 
| - */
 | 
| -Future asyncTime(String logMessage, Future callback(),
 | 
| -                 {bool printTime: false, bool useColors: false}) {
 | 
| -  final watch = new Stopwatch();
 | 
| -  watch.start();
 | 
| -  return callback()..then((_) {
 | 
| -    watch.stop();
 | 
| -    final duration = watch.elapsedMilliseconds;
 | 
| -    if (printTime) {
 | 
| -      _printMessage(logMessage, duration, useColors);
 | 
| -    }
 | 
| -  });
 | 
| -}
 | 
| -
 | 
| -void _printMessage(String logMessage, int duration, bool useColors) {
 | 
| -  var buf = new StringBuffer();
 | 
| -  buf.write(logMessage);
 | 
| -  for (int i = logMessage.length; i < 60; i++) buf.write(' ');
 | 
| -  buf.write(' -- ');
 | 
| -  if (useColors) {
 | 
| -    buf.write(GREEN_COLOR);
 | 
| -  }
 | 
| -  if (duration < 10) buf.write(' ');
 | 
| -  if (duration < 100) buf.write(' ');
 | 
| -  buf..write(duration)..write(' ms');
 | 
| -  if (useColors) {
 | 
| -    buf.write(NO_COLOR);
 | 
| -  }
 | 
| -  print(buf.toString());
 | 
| -}
 | 
| -
 | 
| -// Color constants used for generating messages.
 | 
| -final String GREEN_COLOR = '\u001b[32m';
 | 
| -final String RED_COLOR = '\u001b[31m';
 | 
| -final String MAGENTA_COLOR = '\u001b[35m';
 | 
| -final String NO_COLOR = '\u001b[0m';
 | 
| -
 | 
| -/** A future that waits until all added [Future]s complete. */
 | 
| -// TODO(sigmund): this should be part of the futures/core libraries.
 | 
| -class FutureGroup {
 | 
| -  static const _FINISHED = -1;
 | 
| -
 | 
| -  int _pending = 0;
 | 
| -  Future _failedTask;
 | 
| -  final Completer<List> _completer = new Completer<List>();
 | 
| -  final List results = [];
 | 
| -
 | 
| -  /** Gets the task that failed, if any. */
 | 
| -  Future get failedTask => _failedTask;
 | 
| -
 | 
| -  /**
 | 
| -   * Wait for [task] to complete.
 | 
| -   *
 | 
| -   * If this group has already been marked as completed, you'll get a
 | 
| -   * [StateError].
 | 
| -   *
 | 
| -   * If this group has a [failedTask], new tasks will be ignored, because the
 | 
| -   * error has already been signaled.
 | 
| -   */
 | 
| -  void add(Future task) {
 | 
| -    if (_failedTask != null) return;
 | 
| -    if (_pending == _FINISHED) throw new StateError("Future already completed");
 | 
| -
 | 
| -    _pending++;
 | 
| -    var i = results.length;
 | 
| -    results.add(null);
 | 
| -    task.then((res) {
 | 
| -      results[i] = res;
 | 
| -      if (_failedTask != null) return;
 | 
| -      _pending--;
 | 
| -      if (_pending == 0) {
 | 
| -        _pending = _FINISHED;
 | 
| -        _completer.complete(results);
 | 
| -      }
 | 
| -    }, onError: (e) {
 | 
| -      if (_failedTask != null) return;
 | 
| -      _failedTask = task;
 | 
| -      _completer.completeError(e, getAttachedStackTrace(e));
 | 
| -    });
 | 
| -  }
 | 
| -
 | 
| -  Future<List> get future => _completer.future;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  /**
 | 
| - * Escapes [text] for use in a Dart string.
 | 
| - * [single] specifies single quote `'` vs double quote `"`.
 | 
| - * [triple] indicates that a triple-quoted string, such as `'''` or `"""`.
 | 
| + * Converts a string name with hyphens into an identifier, by removing hyphens
 | 
| + * and capitalizing the following letter. Optionally [startUppercase] to
 | 
| + * captialize the first letter.
 | 
|   */
 | 
| -String escapeDartString(String text, {bool single: true, bool triple: false}) {
 | 
| -  // Note: don't allocate anything until we know we need it.
 | 
| -  StringBuffer result = null;
 | 
| -
 | 
| -  for (int i = 0; i < text.length; i++) {
 | 
| -    int code = text.codeUnitAt(i);
 | 
| -    var replace = null;
 | 
| -    switch (code) {
 | 
| -      case 92/*'\\'*/: replace = r'\\'; break;
 | 
| -      case 36/*r'$'*/: replace = r'\$'; break;
 | 
| -      case 34/*'"'*/:  if (!single) replace = r'\"'; break;
 | 
| -      case 39/*"'"*/:  if (single) replace = r"\'"; break;
 | 
| -      case 10/*'\n'*/: if (!triple) replace = r'\n'; break;
 | 
| -      case 13/*'\r'*/: if (!triple) replace = r'\r'; break;
 | 
| -
 | 
| -      // Note: we don't escape unicode characters, under the assumption that
 | 
| -      // writing the file in UTF-8 will take care of this.
 | 
| -
 | 
| -      // TODO(jmesserly): do we want to replace any other non-printable
 | 
| -      // characters (such as \f) for readability?
 | 
| -    }
 | 
| -
 | 
| -    if (replace != null && result == null) {
 | 
| -      result = new StringBuffer(text.substring(0, i));
 | 
| +String toCamelCase(String hyphenedName, {bool startUppercase: false}) {
 | 
| +  var segments = hyphenedName.split('-');
 | 
| +  int start = startUppercase ? 0 : 1;
 | 
| +  for (int i = start; i < segments.length; i++) {
 | 
| +    var segment = segments[i];
 | 
| +    if (segment.length > 0) {
 | 
| +      // Character between 'a'..'z' mapped to 'A'..'Z'
 | 
| +      segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
 | 
|      }
 | 
| -
 | 
| -    if (result != null) result.write(replace != null ? replace : text[i]);
 | 
|    }
 | 
| -
 | 
| -  return result == null ? text : result.toString();
 | 
| +  return segments.join('');
 | 
|  }
 | 
|  
 | 
| -/** Iterates through an infinite sequence, starting from zero. */
 | 
| -class IntIterator implements Iterator<int> {
 | 
| -  int _next = -1;
 | 
| -
 | 
| -  int get current => _next < 0 ? null : _next;
 | 
| -
 | 
| -  bool moveNext() {
 | 
| -    _next++;
 | 
| -    return true;
 | 
| +/** Reverse of [toCamelCase]. */
 | 
| +String toHyphenedName(String word) {
 | 
| +  var sb = new StringBuffer();
 | 
| +  for (int i = 0; i < word.length; i++) {
 | 
| +    var lower = word[i].toLowerCase();
 | 
| +    if (word[i] != lower && i > 0) sb.write('-');
 | 
| +    sb.write(lower);
 | 
|    }
 | 
| +  return sb.toString();
 | 
|  }
 | 
| 
 |