part of angular.core.parser;

class Lexer {
  static const String QUOTES = "\"'";
  static const String DOT = ".";
  static const String SPECIAL = "(){}[].,;:";
  static const String JSON_SEP = "{,";
  static const String JSON_OPEN = "{[";
  static const String JSON_CLOSE = "}]";
  static const String WHITESPACE = " \r\t\n\v\u00A0";
  static const String EXP_OP = "Ee";
  static const String SIGN_OP = "+-";

  static Map<String, String> ESCAPE =
      {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};

  List<Token> call(String text) {
    List<Token> tokens = [];
    Token token;
    int index = 0;
    int lastIndex;
    int textLength = text.length;
    String ch;
    String lastCh = ":";

    isIn(String charSet, [String c]) =>
      charSet.indexOf(c != null ? c : ch) != -1;
    was(String charSet) => charSet.indexOf(lastCh) != -1;

    cc(String s) => s.codeUnitAt(0);

    bool isNumber([String c]) {
      int cch = cc(c != null ? c : ch);
      return cc('0') <= cch && cch <= cc('9');
    }

    isIdent() {
      int cch = cc(ch);
      return
        cc('a') <= cch && cch <= cc('z') ||
        cc('A') <= cch && cch <= cc('Z') ||
        cc('_') == cch || cch == cc('\$');
    }

    isWhitespace([String c]) => isIn(WHITESPACE, c);
    isExpOperator([String c]) => isIn(SIGN_OP, c) || isNumber(c);

    String peek() => index + 1 < textLength ? text[index + 1] : "EOF";

    lexError(String s) { throw "Lexer Error: $s at column $index in expression [$text]"; }

    // whileChars takes two functions: One called for each character
    // and a second, optional function call at the end of the file.
    // If the first function returns false, the the loop stops and endFn
    // is not run.
    whileChars(fn(), [endFn()]) {
      while (index < textLength) {
        ch = text[index];
        int lastIndex = index;
        if (fn() == false) {
          return;
        }
        if (lastIndex >= index) {
          throw "while chars loop must advance at index $index";
        }
      }
      if (endFn != null) { endFn(); }
    }

    readString() {
      int start = index;

      String string = "";
      String rawString = ch;
      String quote = ch;

      index++;

      whileChars(() {
        rawString += ch;
        if (ch == '\\') {
          index++;
          whileChars(() {
            rawString += ch;
            if (ch == 'u') {
              String hex = text.substring(index + 1, index + 5);
              int charCode = int.parse(hex, radix: 16,
              onError: (s) { lexError('Invalid unicode escape [\\u$hex]'); });
              string += new String.fromCharCode(charCode);
              index += 5;
            } else {
              var rep = ESCAPE[ch];
              if (rep != null) {
                string += rep;
              } else {
                string += ch;
              }
              index++;
            }
            return false; // BREAK
          });
        } else if (ch == quote) {
          index++;
          tokens.add(new Token(start, rawString)
          ..withValue(string));
          return false; // BREAK
        } else {
          string += ch;
          index++;
        }
      }, () {
        lexError('Unterminated quote starting at $start');
      });
    }

    readNumber() {
      String number = "";
      int start = index;
      bool simpleInt = true;
      whileChars(() {
        if (ch == '.') {
          number += ch;
          simpleInt = false;
        } else if (isNumber()) {
          number += ch;
        } else {
          String peekCh = peek();
          if (isIn(EXP_OP) && isExpOperator(peekCh)) {
            simpleInt = false;
            number += ch;
          } else if (isExpOperator() && peekCh != '' && isNumber(peekCh) && isIn(EXP_OP, number[number.length - 1])) {
            simpleInt = false;
            number += ch;
          } else if (isExpOperator() && (peekCh == '' || !isNumber(peekCh)) &&
          isIn(EXP_OP, number[number.length - 1])) {
            lexError('Invalid exponent');
          } else {
            return false; // BREAK
          }
        }
        index++;
      });
      var ret = simpleInt ? int.parse(number) : double.parse(number);
      tokens.add(new Token(start, number)..withValue(ret));
    }

    readIdent() {
      String ident = "";
      int start = index;
      int lastDot = -1, peekIndex = -1;
      String methodName;


      whileChars(() {
        if (ch == '.' || isIdent() || isNumber()) {
          if (ch == '.') {
            lastDot = index;
          }
          ident += ch;
        } else {
          return false; // BREAK
        }
        index++;
      });

      // The identifier had a . in the identifier
      if (lastDot != -1) {
        peekIndex = index;
        while (peekIndex < textLength) {
          String peekChar = text[peekIndex];
          if (peekChar == "(") {
            methodName = ident.substring(lastDot - start + 1);
            ident = ident.substring(0, lastDot - start);
            index = peekIndex;
          }
          if (isWhitespace(peekChar)) {
            peekIndex++;
          } else {
            break;
          }
        }
      }

      var token = new Token(start, ident);

      if (OPERATORS.containsKey(ident)) {
        token.withOp(ident);
      } else {
        token.withGetterSetter(ident);
      }

      tokens.add(token);

      if (methodName != null) {
        tokens.add(new Token(lastDot, '.'));
        tokens.add(new Token(lastDot + 1, methodName));
      }
    }

    oneLexLoop() {
      if (isIn(QUOTES)) {
        readString();
      } else if (isNumber() || isIn(DOT) && isNumber(peek())) {
        readNumber();
      } else if (isIdent()) {
        readIdent();
      } else if (isIn(SPECIAL)) {
        tokens.add(new Token(index, ch));
        index++;
      } else if (isWhitespace()) {
        index++;
      } else {
        // Check for two character operators (e.g. "==")
        String ch2 = ch + peek();

        if (OPERATORS.containsKey(ch2)) {
          tokens.add(new Token(index, ch2)..withOp(ch2));
          index += 2;
        } else if (OPERATORS.containsKey(ch)) {
          tokens.add(new Token(index, ch)..withOp(ch));
          index++;
        } else {
          lexError('Unexpected next character [$ch]');
        }
      }
    }

    whileChars(() {
      oneLexLoop();
    });
    return tokens;
  }
}
library angular.html_parser;

import 'package:html5lib/parser.dart';
import 'package:html5lib/dom.dart';

import 'selector.dart';
import 'io.dart';
import 'common.dart';

typedef NodeVisitor(Node node);

RegExp _MUSTACHE_REGEXP = new RegExp(r'{{([^}]*)}}');
RegExp _NG_REPEAT_SYNTAX = new RegExp(r'^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$');

class HtmlExpressionExtractor {
  List<DirectiveInfo> directiveInfos;
  IoService ioService;

  HtmlExpressionExtractor(this.directiveInfos, IoService this.ioService);

  Set<String> expressions = new Set<String>();

  void crawl(root) {
    ioService.visitFs(root, (String file) {
      if (!file.endsWith('.html')) return;

      String html = ioService.readAsStringSync(file);
      var document = parse(html);
      visitNodes([document], (Node node) {
        if (matchesNode(node, r'[*=/{{.*}}/]')) {
          node.attributes.forEach((attrName, attrValue) {
            _MUSTACHE_REGEXP.allMatches(attrValue).forEach((match) {
              expressions.add(match.group(1));
            });
          });
        }
        if (matchesNode(node, r':contains(/{{.*}}/)')) {
          _MUSTACHE_REGEXP.allMatches(node.value).forEach((match) {
            expressions.add(match.group(1));
          });
        }
        if (matchesNode(node, r'[ng-repeat]')) {
          var expr = _NG_REPEAT_SYNTAX.
              firstMatch(node.attributes['ng-repeat']).group(2);
          expressions.add(expr);
        }

        for (DirectiveInfo directiveInfo in directiveInfos) {
          if (matchesNode(node, directiveInfo.selector)) {
            directiveInfo.expressionAttrs.forEach((attr) {
              if (node.attributes[attr] != null && attr != 'ng-repeat') {
                expressions.add(node.attributes[attr]);
              }
            });
          }
        }
      });
    });
    for (DirectiveInfo directiveInfo in directiveInfos) {
      expressions.addAll(directiveInfo.expressions);
    }
  }

  visitNodes(List<Node> nodes, NodeVisitor visitor) {
    for (Node node in nodes) {
      visitor(node);
      if (node.nodes.length > 0) {
        visitNodes(node.nodes, visitor);
      }
    }
  }
}

part of angular.directive;

/**
 * @ngdoc directive
 * @name ng.directive:a
 * @restrict E
 *
 * @description
 * Modifies the default behavior of the html A tag so that the default action is prevented when
 * the href attribute is empty.
 *
 * This change permits the easy creation of action links with the `ngClick` directive
 * without changing the location or causing page reloads, e.g.:
 * `<a href="" ng-click="model.$save()">Save</a>`
 */
@NgDirective(selector: 'a[href]')
class NgADirective {
  dom.Element element;

  NgADirective(dom.Element element) {
    if (element.attributes["href"] == "") {
      element.onClick.listen((event) {
        if (element.attributes["href"] == "") {
          event.preventDefault();
        }
      });
    }
  }
}
part of angular.core.dom;

List<dom.Node> cloneElements(elements) {
  var clones = [];
  for(var i = 0, ii = elements.length; i < ii; i++) {
    clones.add(elements[i].clone(true));
  }
  return clones;
}

class DirectiveRef {
  final dom.Node element;
  final Type type;
  final NgAnnotation annotation;
  final String value;

  BlockFactory blockFactory;

  DirectiveRef(dom.Node this.element, Type this.type, NgAnnotation this.annotation,
               [ String this.value ]);

  String toString() {
    var html = element is dom.Element ? (element as dom.Element).outerHtml : element.nodeValue;
    return '{ element: $html, selector: ${annotation.selector}, value: $value }';
  }
}

part of angular.directive;

/**
 * Creates a binding that will innerHTML the result of evaluating the
 * `expression` bound to `ng-bind-html` into the current element in a secure
 * way.  This expression must evaluate to a string.  The innerHTML-ed content
 * will be sanitized using a default [NodeValidator] constructed as `new
 * dom.NodeValidatorBuilder.common()`.  In a future version, when Strict
 * Contextual Escaping support has been added to Angular.dart, this directive
 * will allow one to bypass the sanitizaton and innerHTML arbitrary trusted
 * HTML.
 *
 * Example:
 *
 *     <div ng-bind-html="htmlVar"></div>
 */
@NgDirective(
  selector: '[ng-bind-html]',
  map: const {'ngBindHtml': '=.value'})
class NgBindHtmlDirective {
  // The default HTML sanitizer.  Eventually, we'll make this configurable or
  // use an optionally loaded `$sanitize` service.
  static final dom.NodeValidator validator = new dom.NodeValidatorBuilder.common();

  dom.Element element;

  NgBindHtmlDirective(dom.Element this.element);

  /**
   * Parsed expression from the `ng-bind-html` attribute.  The result of this
   * expression is innerHTML'd according to the rules specified in this class'
   * documention.
   */
  set value(value) => element.setInnerHtml((value == null ? '' : value.toString()),
                                           validator: validator) ;
}
library mirrors;

import 'dart:mirrors';
export 'dart:mirrors';

Map<Symbol, ClassMirror> _classMirrorCache = new Map<Symbol, ClassMirror>();

const List<Symbol> PRIMITIVE_TYPES = const <Symbol>[
  const Symbol('dart.core.dynamic'), const Symbol('dart.core.num'),
  const Symbol('dart.core.int'), const Symbol('dart.core.double'),
  const Symbol('dart.core.String'), const Symbol('dart.core.bool')
];

const Map<String, String> _PRIMITIVE_TYPE_SIMPLE_NAMES = const {
  'dart.core.dynamic': 'dynamic',
  'dart.core.num': 'num',
  'dart.core.int': 'int',
  'dart.core.double': 'double',
  'dart.core.String': 'String',
  'dart.core.bool': 'bool'
};

// Hack because we can't get a [ClassMirror] from a [Symbol].
ClassMirror getClassMirrorBySymbol(Symbol id) {
  var mirror = _classMirrorCache[id];
  if (mirror == null) {
    for (var lib in currentMirrorSystem().libraries.values) {
      for (ClassMirror cls in lib.classes.values) {
        if (cls.qualifiedName == id) {
          mirror = cls;
          break;
        }
      }
    }
    _classMirrorCache[id] = mirror;
  }
  return mirror;
}

String getSymbolName(Symbol symbol) => MirrorSystem.getName(symbol);

String getSymbolSimpleName(Symbol symbol) {
  if (PRIMITIVE_TYPES.contains(symbol)) {
    return _PRIMITIVE_TYPE_SIMPLE_NAMES[getSymbolName(symbol)];
  }
  return MirrorSystem.getName(getClassMirrorBySymbol(symbol).simpleName);
}

Map<Type, ClassMirror> _reflectionCache = new Map<Type, ClassMirror>();

/// Cached version of [reflectClass].
ClassMirror cachedReflectClass(Type type) {
  ClassMirror mirror = _reflectionCache[type];
  if (mirror == null) {
    mirror = reflectClass(type);
    _reflectionCache[type] = mirror;
  }
  return mirror;
}

Symbol getTypeSymbol(Type type) => cachedReflectClass(type).qualifiedName;
part of angular.directive;

/**
 * The [NgBindTemplateDirective] specifies that the element text content should be replaced with
 * the interpolation of the template in the ngBindTemplate attribute. Unlike ngBind, the
 * ngBindTemplate can contain multiple {{ }} expressions.
 */
@NgDirective(
  selector: '[ng-bind-template]',
  map: const {'ng-bind-template': '@.bind'})
class NgBindTemplateDirective {
  dom.Element element;

  NgBindTemplateDirective(dom.Element this.element);

  set bind(value) {
    element.text = value;
  }
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script>
    if (!navigator.webkitStartDart || !navigator.webkitStartDart()) {
      var message = "This example must be run in the latest build of Dartium.";
      window.onload = function() { document.body.innerHTML = message; }
      alert(message);
    }
  </script>
  <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
  <script src="main.dart" type="application/dart"></script>
  <title>test_filter_filter</title>
</head>
<body class="container"><div class="row" toy-data>
  <h3>Angular.Dart: filter</h3>
  Search: <input type="text" ng-model="searchText">
  <table id="searchTextResults">
    <tr><th>Name</th><th>Phone</th></tr>
    <tr ng-repeat="friend in friends | filter:searchText">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
    </tr>
  </table>
  <hr>
  Any: <input type="text" ng-model="search.$"> <br>
  Name only <input type="text" ng-model="search.name"><br>
  Phone only <input type="text" ng-model="search.phone"><br>
  <table id="searchObjResults">
    <tr><th>Name</th><th>Phone</th></tr>
    <tr ng-repeat="friend in friends | filter:search:strict">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
    </tr>
  </table>
</div></body>
</html>
library angular.playback.playback_http;

import "dart:async";
import "dart:html";
import "dart:json" as json;

import "package:angular/core_dom/module.dart";
import "package:angular/mock/module.dart" as mock;

import "playback_data.dart" as playback_data;

class PlaybackHttpBackendConfig {
  requestKey(String url,
                 {String method, bool withCredentials, String responseType,
                 String mimeType, Map<String, String> requestHeaders, sendData,
                 void onProgress(ProgressEvent e)}) {
    return json.stringify({
        "url": url,
        "method": method,
        "requestHeaders": requestHeaders,
        "data": sendData
    });
  }
}

// HELP! The DI system is getting in the way.  We want
// the HttpBackend, but it will be implemented by ourselves.
class HttpBackendWrapper {
  HttpBackend backend;
  HttpBackendWrapper(HttpBackend this.backend);
}

class RecordingHttpBackend implements HttpBackend {

  HttpBackend _prodBackend;
  PlaybackHttpBackendConfig _config;

  RecordingHttpBackend(HttpBackendWrapper wrapper,
                       PlaybackHttpBackendConfig this._config) {
    this._prodBackend = wrapper.backend;

  }

  Future request(String url,
                 {String method, bool withCredentials, String responseType,
                 String mimeType, Map<String, String> requestHeaders, sendData,
                 void onProgress(ProgressEvent e)}) {
    return _prodBackend.request(url,
        method: method,
        withCredentials: withCredentials,
        responseType: responseType,
        mimeType: mimeType,
        requestHeaders: requestHeaders,
        sendData: sendData,
        onProgress: onProgress).then((HttpRequest r) {

     var key = _config.requestKey(url,
        method: method,
        withCredentials: withCredentials,
        responseType: responseType,
        mimeType: mimeType,
        requestHeaders: requestHeaders,
        sendData: sendData,
        onProgress: onProgress);

      assert(key is String);
      _prodBackend.request('/record',  //TODO make this URL configurable.
        method: 'POST', sendData: json.stringify({
          "key": key, "data": json.stringify({
              "status": r.status,
              "headers": r.getAllResponseHeaders(),
              "data": r.responseText})
      }));
      return r;
    });
  }
}

class PlaybackHttpBackend implements HttpBackend {

  PlaybackHttpBackendConfig _config;

  PlaybackHttpBackend(PlaybackHttpBackendConfig this._config);

  Map data = playback_data.playbackData;

  Future request(String url,
                 {String method, bool withCredentials, String responseType,
                 String mimeType, Map<String, String> requestHeaders, sendData,
                 void onProgress(ProgressEvent e)}) {
    var key = _config.requestKey(url,
        method: method,
        withCredentials: withCredentials,
        responseType: responseType,
        mimeType: mimeType,
        requestHeaders: requestHeaders,
        sendData: sendData,
        onProgress: onProgress);

    if (!data.containsKey(key)) {
      throw ["Request is not recorded $key"];
    }
    var playback = data[key];
    return new Future.value(
        new mock.MockHttpRequest(
            playback['status'],
            playback['data'],
            playback['headers']));
  }
}
part of angular.core.dom;

class NodeCursor {
  List<dynamic> stack = [];
  List<dom.Node> elements;
  num index;

  NodeCursor(List<dom.Node> this.elements) {
    index = 0;
  }

  isValid() {
    return index < elements.length;
  }

  cursorSize() {
    return 1;
  }

  macroNext() {
    for(var i = 0, ii = cursorSize(); i < ii; i++, index++){}

    return this.isValid();
  }

  microNext() {
    var length = elements.length;

    if (index < length) {
      index++;
    }

    return index < length;
  }

  nodeList() {
    if (!isValid()) return [];  // or should we return null?

    var nodes = [];

    for(var i = 0, ii = cursorSize(); i < ii; i++) {
      nodes.add(elements[index + i]);
    }

    return nodes;
  }

  descend() {
    var childNodes = elements[index].nodes;
    var hasChildren = !!(childNodes != null && childNodes.length > 0);

    if (hasChildren) {
      stack.add(index);
      stack.add(elements);
      elements = new List.from(childNodes);
      index = 0;
    }

    return hasChildren;
  }

  ascend() {
    elements = stack.removeLast();
    index = stack.removeLast();
  }

  insertAnchorBefore(String name) {
    var current = elements[index];
    var parent = current.parentNode;

    var anchor = new dom.Comment('ANCHOR: $name');

    elements.insert(index++, anchor);

    if (parent != null) {
      parent.insertBefore(anchor, current);
    }
  }

  replaceWithAnchor(String name) {
    insertAnchorBefore(name);
    var childCursor = remove();
    this.index--;
    return childCursor;
  }

  remove() {
    var nodes = nodeList();

    for (var i = 0, ii = nodes.length; i < ii; i++) {
      // NOTE(deboer): If elements is a list of child nodes on a node, then
      // calling Node.remove() may also remove it from the list.  Thus, we
      // call elements.removeAt first so only one node is removed.
      elements.removeAt(index);
      nodes[i].remove();
    }

    return new NodeCursor(nodes);
  }

  isInstance() {
    return false;
  }
}
part of angular.directive;

/**
  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
  *
  * @example
        <span ng-style="{color:'red'}">Sample Text</span>
  */
@NgDirective(
    selector: '[ng-style]',
    map: const { 'ng-style': '@.styleExpression'})
class NgStyleDirective {
  dom.Element _element;
  Scope _scope;

  String _styleExpression;

  NgStyleDirective(dom.Element this._element, Scope this._scope);

  Function _removeWatch = () => null;
  var _lastStyles;

/**
  * ng-style attribute takes an expression hich evals to an
  *      object whose keys are CSS style names and values are corresponding values for those CSS
  *      keys.
  */
  set styleExpression(String value) {
    _styleExpression = value;
    _removeWatch();
    _removeWatch = _scope.$watchCollection(_styleExpression, _onStyleChange);
  }

  _onStyleChange(Map newStyles) {
    dom.CssStyleDeclaration css = _element.style;
    if (_lastStyles != null) {
      _lastStyles.forEach((val, style) { css.setProperty(val, ''); });
    }
    _lastStyles = newStyles;

    if (newStyles != null) {
      newStyles.forEach((val, style) { css.setProperty(val, style); });
    }
  }
}
// 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 date_symbols;

/**
 * This holds onto information about how a particular locale formats dates. It
 * contains mostly strings, e.g. what the names of months or weekdays are,
 * but also indicates things like the first day of the week. We expect the data
 * for instances of these to be generated out of ICU or a similar reference
 * source. This is used in conjunction with the date_time_patterns, which
 * defines for a particular locale the different named formats that will
 * make use of this data.
 */
class DateSymbols {
  String NAME;
  List<String> ERAS, ERANAMES, NARROWMONTHS, STANDALONENARROWMONTHS,
      MONTHS, STANDALONEMONTHS, SHORTMONTHS, STANDALONESHORTMONTHS, WEEKDAYS,
      STANDALONEWEEKDAYS, SHORTWEEKDAYS, STANDALONESHORTWEEKDAYS,
      NARROWWEEKDAYS, STANDALONENARROWWEEKDAYS, SHORTQUARTERS,
      QUARTERS, AMPMS, DATEFORMATS, TIMEFORMATS;
  Map<String, String> AVAILABLEFORMATS;
  int FIRSTDAYOFWEEK;
  List<int> WEEKENDRANGE;
  int FIRSTWEEKCUTOFFDAY;

  DateSymbols({this.NAME,
               this.ERAS,
               this.ERANAMES,
               this.NARROWMONTHS,
               this.STANDALONENARROWMONTHS,
               this.MONTHS,
               this.STANDALONEMONTHS,
               this.SHORTMONTHS,
               this.STANDALONESHORTMONTHS,
               this.WEEKDAYS,
               this.STANDALONEWEEKDAYS,
               this.SHORTWEEKDAYS,
               this.STANDALONESHORTWEEKDAYS,
               this.NARROWWEEKDAYS,
               this.STANDALONENARROWWEEKDAYS,
               this.SHORTQUARTERS,
               this.QUARTERS,
               this.AMPMS,
               // TODO(alanknight): These formats are taken from Closure,
               // where there's only a fixed set of available formats.
               // Here we have the patterns separately. These should
               // either be used, or removed.
               this.DATEFORMATS,
               this.TIMEFORMATS,
               this.AVAILABLEFORMATS,
               this.FIRSTDAYOFWEEK,
               this.WEEKENDRANGE,
               this.FIRSTWEEKCUTOFFDAY});

  // TODO(alanknight): Replace this with use of a more general serialization
  // facility once one is available. Issue 4926.
  DateSymbols.deserializeFromMap(Map map) {
    NAME = map["NAME"];
    ERAS = map["ERAS"];
    ERANAMES = map["ERANAMES"];
    NARROWMONTHS = map["NARROWMONTHS"];
    STANDALONENARROWMONTHS = map["STANDALONENARROWMONTHS"];
    MONTHS = map["MONTHS"];
    STANDALONEMONTHS = map["STANDALONEMONTHS"];
    SHORTMONTHS = map["SHORTMONTHS"];
    STANDALONESHORTMONTHS = map["STANDALONESHORTMONTHS"];
    WEEKDAYS = map["WEEKDAYS"];
    STANDALONEWEEKDAYS = map["STANDALONEWEEKDAYS"];
    SHORTWEEKDAYS = map["SHORTWEEKDAYS"];
    STANDALONESHORTWEEKDAYS = map["STANDALONESHORTWEEKDAYS"];
    NARROWWEEKDAYS = map["NARROWWEEKDAYS"];
    STANDALONENARROWWEEKDAYS = map["STANDALONENARROWWEEKDAYS"];
    SHORTQUARTERS = map["SHORTQUARTERS"];
    QUARTERS = map["QUARTERS"];
    AMPMS = map["AMPMS"];
    DATEFORMATS = map["DATEFORMATS"];
    TIMEFORMATS = map["TIMEFORMATS"];
    AVAILABLEFORMATS = map["AVAILABLEFORMATS"];
    FIRSTDAYOFWEEK = map["FIRSTDAYOFWEEK"];
    WEEKENDRANGE = map["WEEKENDRANGE"];
    FIRSTWEEKCUTOFFDAY = map["FIRSTWEEKCUTOFFDAY"];
  }

  Map serializeToMap() {
    var map = new Map();
    map["NAME"] = NAME;
    map["ERAS"] = ERAS;
    map["ERANAMES"] = ERANAMES;
    map["NARROWMONTHS"] = NARROWMONTHS;
    map["STANDALONENARROWMONTHS"] = STANDALONENARROWMONTHS;
    map["MONTHS"] = MONTHS;
    map["STANDALONEMONTHS"] = STANDALONEMONTHS;
    map["SHORTMONTHS"] = SHORTMONTHS;
    map["STANDALONESHORTMONTHS"] = STANDALONESHORTMONTHS;
    map["WEEKDAYS"] = WEEKDAYS;
    map["STANDALONEWEEKDAYS"] = STANDALONEWEEKDAYS;
    map["SHORTWEEKDAYS"] = SHORTWEEKDAYS;
    map["STANDALONESHORTWEEKDAYS"] = STANDALONESHORTWEEKDAYS;
    map["NARROWWEEKDAYS"] = NARROWWEEKDAYS;
    map["STANDALONENARROWWEEKDAYS"] = STANDALONENARROWWEEKDAYS;
    map["SHORTQUARTERS"] = SHORTQUARTERS;
    map["QUARTERS"] = QUARTERS;
    map["AMPMS"] = AMPMS;
    map["DATEFORMATS"] = DATEFORMATS;
    map["TIMEFORMATS"] = TIMEFORMATS;
    map["AVAILABLEFORMATS"] = AVAILABLEFORMATS;
    map["FIRSTDAYOFWEEK"] = FIRSTDAYOFWEEK;
    map["WEEKENDRANGE"] = WEEKENDRANGE;
    map["FIRSTWEEKCUTOFFDAY"] = FIRSTWEEKCUTOFFDAY;
    return map;
  }

  toString() => NAME;
}

/**
 * We hard-code the locale data for en_US here so that there's at least one
 * locale always available.
 */
var en_USSymbols = new DateSymbols(
    NAME: "en_US",
    ERAS: const [ 'BC', 'AD'],
    ERANAMES: const [ 'Before Christ', 'Anno Domini'],
    NARROWMONTHS: const [ 'J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',
         'N', 'D'],
    STANDALONENARROWMONTHS: const [ 'J', 'F', 'M', 'A', 'M', 'J', 'J', 'A',
         'S', 'O', 'N', 'D'],
    MONTHS: const [ 'January', 'February', 'March', 'April', 'May', 'June',
         'July', 'August', 'September', 'October', 'November', 'December'],
    STANDALONEMONTHS: const [ 'January', 'February', 'March', 'April', 'May',
         'June', 'July', 'August', 'September', 'October', 'November',
         'December'],
    SHORTMONTHS: const [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
         'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    STANDALONESHORTMONTHS: const [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
         'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    WEEKDAYS: const [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
         'Friday', 'Saturday'],
    STANDALONEWEEKDAYS: const [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday',
         'Thursday', 'Friday', 'Saturday'],
    SHORTWEEKDAYS: const [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
    STANDALONESHORTWEEKDAYS: const [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri',
         'Sat'],
    NARROWWEEKDAYS: const [ 'S', 'M', 'T', 'W', 'T', 'F', 'S'],
    STANDALONENARROWWEEKDAYS: const [ 'S', 'M', 'T', 'W', 'T', 'F', 'S'],
    SHORTQUARTERS: const [ 'Q1', 'Q2', 'Q3', 'Q4'],
    QUARTERS: const [ '1st quarter', '2nd quarter', '3rd quarter',
         '4th quarter'],
    AMPMS: const [ 'AM', 'PM'],
    DATEFORMATS: const [ 'EEEE, MMMM d, y', 'MMMM d, y', 'MMM d, y',
         'M/d/yy'],
    TIMEFORMATS: const [ 'h:mm:ss a zzzz', 'h:mm:ss a z', 'h:mm:ss a',
         'h:mm a'],
    FIRSTDAYOFWEEK: 6,
    WEEKENDRANGE: const [5, 6],
    FIRSTWEEKCUTOFFDAY: 5);

var en_USPatterns = const {
  'd': 'd', // DAY
  'E': 'EEE', // ABBR_WEEKDAY
  'EEEE': 'EEEE', // WEEKDAY
  'LLL': 'LLL', // ABBR_STANDALONE_MONTH
  'LLLL': 'LLLL', // STANDALONE_MONTH
  'M': 'L', // NUM_MONTH
  'Md': 'M/d', // NUM_MONTH_DAY
  'MEd': 'EEE, M/d', // NUM_MONTH_WEEKDAY_DAY
  'MMM': 'LLL', // ABBR_MONTH
  'MMMd': 'MMM d', // ABBR_MONTH_DAY
  'MMMEd': 'EEE, MMM d', // ABBR_MONTH_WEEKDAY_DAY
  'MMMM': 'LLLL', // MONTH
  'MMMMd': 'MMMM d', // MONTH_DAY
  'MMMMEEEEd': 'EEEE, MMMM d', // MONTH_WEEKDAY_DAY
  'QQQ': 'QQQ', // ABBR_QUARTER
  'QQQQ': 'QQQQ', // QUARTER
  'y': 'y', // YEAR
  'yM': 'M/y', // YEAR_NUM_MONTH
  'yMd': 'M/d/y', // YEAR_NUM_MONTH_DAY
  'yMEd': 'EEE, M/d/y', // YEAR_NUM_MONTH_WEEKDAY_DAY
  'yMMM': 'MMM y', // YEAR_ABBR_MONTH
  'yMMMd': 'MMM d, y', // YEAR_ABBR_MONTH_DAY
  'yMMMEd': 'EEE, MMM d, y', // YEAR_ABBR_MONTH_WEEKDAY_DAY
  'yMMMM': 'MMMM y', // YEAR_MONTH
  'yMMMMd': 'MMMM d, y', // YEAR_MONTH_DAY
  'yMMMMEEEEd': 'EEEE, MMMM d, y', // YEAR_MONTH_WEEKDAY_DAY
  'yQQQ': 'QQQ y', // YEAR_ABBR_QUARTER
  'yQQQQ': 'QQQQ y', // YEAR_QUARTER
  'H': 'HH', // HOUR24
  'Hm': 'HH:mm', // HOUR24_MINUTE
  'Hms': 'HH:mm:ss', // HOUR24_MINUTE_SECOND
  'j': 'h a', // HOUR
  'jm': 'h:mm a', // HOUR_MINUTE
  'jms': 'h:mm:ss a', // HOUR_MINUTE_SECOND
  'jmv': 'h:mm a v', // HOUR_MINUTE_GENERIC_TZ
  'jmz': 'h:mm a z', // HOUR_MINUTETZ
  'jz': 'h a z', // HOURGENERIC_TZ
  'm': 'm', // MINUTE
  'ms': 'mm:ss', // MINUTE_SECOND
  's': 's', // SECOND
  'v': 'v', // ABBR_GENERIC_TZ
  'z': 'z', // ABBR_SPECIFIC_TZ
  'zzzz': 'zzzz', // SPECIFIC_TZ
  'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
};
// 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.

/**
 * Constants for use in metadata annotations such as
 * `@deprecated`, `@override`, and `@proxy`.
 * 
 * Annotations provide semantic information
 * that tools can use to provide a better user experience.
 * For example, an IDE might not autocomplete
 * the name of a function that's been marked `@deprecated`,
 * or it might display the function's name differently.
 *
 * For information on installing and importing this library, see the
 * [meta package on pub.dartlang.org]
 * (http://pub.dartlang.org/packages/meta).
 * For examples of using annotations, see
 * [Metadata](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-metadata)
 * in the language tour.
 */
library meta;

/**
 * An annotation used to mark a class, field, getter, setter, method, top-level
 * variable, or top-level function as one that should no longer be used. Tools
 * can use this annotation to provide a warning on references to the marked
 * element.
 */
const deprecated = const _Deprecated();

class _Deprecated {
  const _Deprecated();
}

/**
 * An annotation used to mark an instance member (method, field, getter or
 * setter) as overriding an inherited class member. Tools can use this
 * annotation to provide a warning if there is no overridden member.
 */
const override = const _Override();

class _Override {
  const _Override();
}

/**
 * An annotation used to mark a class that should be considered to implement
 * every possible getter, setter and method. Tools can use this annotation to
 * suppress warnings when there is no explicit implementation of a referenced
 * member. Tools should provide a hint if this annotation is applied to a class
 * that does not implement or inherit an implementation of the method
 * [:noSuchMethod:] (other than the implementation in [Object]). Note that
 * classes are not affected by the use of this annotation on a supertype.
 */
const proxy = const _Proxy();

class _Proxy {
  const _Proxy();
}
// 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.

/**
 * This library provides internationalization and localization. This includes
 * message formatting and replacement, date and number formatting and parsing,
 * and utilities for working with Bidirectional text.
 *
 * ## Installing ##
 *
 * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
 * file.
 *
 *     dependencies:
 *       intl: any
 *
 * Then run `pub install`.
 *
 * For more information, see the
 * [intl package on pub.dartlang.org](http://pub.dartlang.org/packages/intl).
 *
 * For things that require locale or other data, there are multiple different
 * ways of making that data available, which may require importing different
 * libraries. See the class comments for more details.
 *
 * There is also a simple example application that can be found in the
 * `example/basic` directory.
 *
 * [pub]: http://pub.dartlang.org
 */
library intl;

import 'dart:collection';
import 'dart:convert';
import 'package:meta/meta.dart';
import 'src/intl_helpers.dart';
import 'dart:math';
import 'date_symbols.dart';
import 'src/date_format_internal.dart';
import "number_symbols.dart";
import "number_symbols_data.dart";

part 'date_format.dart';
part 'src/date_format_field.dart';
part 'src/date_format_helpers.dart';
part 'bidi_formatter.dart';
part 'bidi_utils.dart';
part 'number_format.dart';

/**
 * The Intl class provides a common entry point for internationalization
 * related tasks. An Intl instance can be created for a particular locale
 * and used to create a date format via `anIntl.date()`. Static methods
 * on this class are also used in message formatting.
 *
 * Message example:
 *     '''I see ${Intl.plural(num_people,
 *               {'0': 'no one at all',
 *                '1': 'one other person',
 *                'other': '$num_people other people'})} in $place.''''
 *
 * Usage examples:
 *      today(date) => Intl.message(
 *          "Today's date is $date",
 *          name: 'today',
 *          args: [date],
 *          desc: 'Indicate the current date',
 *          examples: {'date' : 'June 8, 2012'});
 *      print(today(new DateTime.now());
 *
 *      msg(num_people, place) => Intl.message(
 *           '''I see ${Intl.plural(num_people,
 *             {'0': 'no one at all',
 *              '1': 'one other person',
 *              'other': '$num_people other people'})} in $place.''',
 *          name: 'msg',
 *          args: [num_people, place],
 *          desc: 'Description of how many people are seen as program start.',
 *          examples: {'num_people': 3, 'place': 'London'});
 *
 * Calling `msg(2, 'Athens');` would
 * produce "I see 2 other people in Athens." as output in the default locale.
 *
 * To use a locale other than the default, use the `withLocale` function.
 * You can set the default locale.
 *       Intl.defaultLocale = "pt_BR";
 *
 * To temporarily use a locale other than the default, use the `withLocale`
 * function.
 *       var todayString = new DateFormat("pt_BR").format(new DateTime.now());
 *       print(withLocale("pt_BR", () => today(todayString));
 *
 * See `tests/message_format_test.dart` for more examples.
 */
 //TODO(efortuna): documentation example involving the offset parameter?

class Intl {
  /**
   * String indicating the locale code with which the message is to be
   * formatted (such as en-CA).
   */
  String _locale;

  /** The default locale. This defaults to being set from systemLocale, but
   * can also be set explicitly, and will then apply to any new instances where
   * the locale isn't specified.
   */
  static String defaultLocale;

  /**
   * The system's locale, as obtained from the window.navigator.language
   * or other operating system mechanism. Note that due to system limitations
   * this is not automatically set, and must be set by importing one of
   * intl_browser.dart or intl_standalone.dart and calling findSystemLocale().
   */
  static String systemLocale = 'en_US';

  /**
   * Return a new date format using the specified [pattern].
   * If [desiredLocale] is not specified, then we default to [locale].
   */
  DateFormat date([String pattern, String desiredLocale]) {
    var actualLocale = (desiredLocale == null) ? locale : desiredLocale;
    return new DateFormat(pattern, actualLocale);
  }

  /**
   * Constructor optionally [aLocale] for specifics of the language
   * locale to be used, otherwise, we will attempt to infer it (acceptable if
   * Dart is running on the client, we can infer from the browser/client
   * preferences).
   */
  Intl([String aLocale]) {
    if (aLocale != null) {
      _locale = aLocale;
    } else {
      _locale = getCurrentLocale();
    }
  }

  /**
   * Returns a message that can be internationalized. It takes a
   * [message_str] that will be translated, which may be interpolated
   * based on one or more variables, a [desc] providing a description of usage
   * for the [message_str], and a map of [examples] for each data element to be
   * substituted into the message. For example, if message="Hello, $name", then
   * examples = {'name': 'Sparky'}. If not using the user's default locale, or
   * if the locale is not easily detectable, explicitly pass [locale].
   * The values of [desc] and [examples] are not used at run-time but are only
   * made available to the translators, so they MUST be simple Strings available
   * at compile time: no String interpolation or concatenation.
   * The expected usage of this is inside a function that takes as parameters
   * the variables used in the interpolated string, and additionally also a
   * locale (optional).
   * Ultimately, the information about the enclosing function and its arguments
   * will be extracted automatically but for the time being it must be passed
   * explicitly in the [name] and [args] arguments.
   */
  static String message(String message_str, {final String desc: '',
      final Map examples: const {}, String locale, String name,
      List<String> args}) {
    return messageLookup.lookupMessage(
        message_str, desc, examples, locale, name, args);
  }

  /**
   * Return the locale for this instance. If none was set, the locale will
   * be the default.
   */
  String get locale => _locale;

  /**
   * Return true if the locale exists, or if it is null. The null case
   * is interpreted to mean that we use the default locale.
   */
  static bool _localeExists(localeName) {
    return DateFormat.localeExists(localeName);
  }

  /**
   * Given [newLocale] return a locale that we have data for that is similar
   * to it, if possible.
   * If [newLocale] is found directly, return it. If it can't be found, look up
   * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-'
   * as a separator and changes it into '_' for lookup, and changes the
   * country to uppercase.
   * Note that null is interpreted as meaning the default locale, so if
   * [newLocale] is null it will be returned.
   */
  static String verifiedLocale(String newLocale, Function localeExists,
                               {Function onFailure: _throwLocaleError}) {
    // TODO(alanknight): Previously we kept a single verified locale on the Intl
    // object, but with different verification for different uses, that's more
    // difficult. As a result, we call this more often. Consider keeping
    // verified locales for each purpose if it turns out to be a performance
    // issue.
    if (newLocale == null) return getCurrentLocale();
    if (localeExists(newLocale)) {
      return newLocale;
    }
    for (var each in
        [canonicalizedLocale(newLocale), shortLocale(newLocale)]) {
      if (localeExists(each)) {
        return each;
      }
    }
    return onFailure(newLocale);
  }

  /**
   * The default action if a locale isn't found in verifiedLocale. Throw
   * an exception indicating the locale isn't correct.
   */
  static String _throwLocaleError(String localeName) {
    throw new ArgumentError("Invalid locale '$localeName'");
  }

  /** Return the short version of a locale name, e.g. 'en_US' => 'en' */
  static String shortLocale(String aLocale) {
    if (aLocale.length < 2) return aLocale;
    return aLocale.substring(0, 2).toLowerCase();
  }

  /**
   * Return the name [aLocale] turned into xx_YY where it might possibly be
   * in the wrong case or with a hyphen instead of an underscore. If
   * [aLocale] is null, for example, if you tried to get it from IE,
   * return the current system locale.
   */
  static String canonicalizedLocale(String aLocale) {
    // Locales of length < 5 are presumably two-letter forms, or else malformed.
    // Locales of length > 6 are likely to be malformed. In either case we
    // return them unmodified and if correct they will be found.
    // We treat C as a special case, and assume it wants en_ISO for formatting.
    // TODO(alanknight): en_ISO is probably not quite right for the C/Posix
    // locale for formatting. Consider adding C to the formats database.
    if (aLocale == null) return systemLocale;
    if (aLocale == "C") return "en_ISO";
    if ((aLocale.length < 5) || (aLocale.length > 6)) return aLocale;
    if (aLocale[2] != '-' && (aLocale[2] != '_')) return aLocale;
    var lastRegionLetter = aLocale.length == 5 ? "" : aLocale[5].toUpperCase();
    return '${aLocale[0]}${aLocale[1]}_${aLocale[3].toUpperCase()}'
           '${aLocale[4].toUpperCase()}$lastRegionLetter';
  }

  /**
   * Format a message differently depending on [howMany]. Normally used
   * as part of an `Intl.message` text that is to be translated.
   * Selects the correct plural form from
   * the provided alternatives. The [other] named argument is mandatory.
   */
  static String plural(int howMany, {zero, one, two, few, many, other,
      desc, examples, locale, name, args}) {
    // If we are passed a name and arguments, then we are operating as a
    // top-level message, so look up our translation by calling Intl.message
    // with ourselves as an argument.
    if (name != null) {
      return message(
        plural(howMany,
            zero: zero, one: one, two: two, few: few, many: many, other: other),
        name: name,
        args: args,
        locale: locale);
    }
    if (other == null) {
      throw new ArgumentError("The 'other' named argument must be provided");
    }
    // TODO(alanknight): This algorithm needs to be locale-dependent.
    switch (howMany) {
      case 0 : return (zero == null) ? other : zero;
      case 1 : return (one == null) ? other : one;
      case 2: return (two == null) ? ((few == null) ? other : few) : two;
      default:
        if (howMany == 3 || howMany == 4 && few != null) return few;
        if (howMany > 10 && howMany < 100 && many != null) return many;
        return other;
    }
    throw new ArgumentError("Invalid plural usage for $howMany");
  }

  /**
   * Format a message differently depending on [targetGender]. Normally used as
   * part of an Intl.message message that is to be translated.
   */
  static String gender(String targetGender,
      {String male, String female, String other,
       String desc, Map examples, String locale, String name,
       List<String>args}) {
    // If we are passed a name and arguments, then we are operating as a
    // top-level message, so look up our translation by calling Intl.message
    // with ourselves as an argument.
    if (name != null) {
      return message(
        gender(targetGender, male: male, female: female, other: other),
        name: name,
        args: args,
        locale: locale);
    }

    if (other == null) {
      throw new ArgumentError("The 'other' named argument must be specified");
    }
    switch(targetGender) {
      case "female" : return female == null ? other : female;
      case "male" : return male == null ? other : male;
      default: return other;
    }
  }

  /**
   * Format a message differently depending on [choice]. We look up the value
   * of [choice] in [cases] and return the result, or an empty string if
   * it is not found. Normally used as part
   * of an Intl.message message that is to be translated.
   */
  static String select(String choice, Map<String, String> cases,
       {String desc, Map examples, String locale, String name,
       List<String>args}) {
    // If we are passed a name and arguments, then we are operating as a
    // top-level message, so look up our translation by calling Intl.message
    // with ourselves as an argument.
    if (name != null) {
      return message(
          select(choice, cases),
          name: name,
          args: args,
          locale: locale);
    }
    var exact = cases[choice];
    if (exact != null) return exact;
    var other = cases["other"];
    if (other == null)
      throw new ArgumentError("The 'other' case must be specified");
    return other;
  }

  /**
   * Format the given function with a specific [locale], given a
   * [message_function] that takes no parameters. The [message_function] can be
   * a simple message function that just returns the result of `Intl.message()`
   * it can be a wrapper around a message function that takes arguments, or it
   * can be something more complex that manipulates multiple message
   * functions.
   *
   * In either case, the purpose of this is to delay calling [message_function]
   * until the proper locale has been set. This returns the result of calling
   * [message_function], which could be of an arbitrary type.
   */
  static withLocale(String locale, Function message_function) {
    // We have to do this silliness because Locale is not known at compile time,
    // but must be a static variable in order to be visible to the Intl.message
    // invocation.
    var oldLocale = getCurrentLocale();
    defaultLocale = locale;
    var result = message_function();
    defaultLocale = oldLocale;
    return result;
  }

  /**
   * Accessor for the current locale. This should always == the default locale,
   * unless for some reason this gets called inside a message that resets the
   * locale.
   */
  static String getCurrentLocale() {
    if (defaultLocale == null) defaultLocale = systemLocale;
    return defaultLocale;
  }

  toString() => "Intl($locale)";
}
part of angular.core.dom;

/**
* ElementWrapper is an interface for [Block]s and [BlockHole]s. Its purpose is
* to allow treating [Block] and [BlockHole] under same interface so that
* [Block]s can be added after [BlockHole].
*/
abstract class ElementWrapper {
  List<dom.Node> elements;
  ElementWrapper next;
  ElementWrapper previous;
}

/**
 * A Block is a fundamental building block of DOM. It is a chunk of DOM which
 * Can not be structural changed. It can only have its attributes changed.
 * A Block can have [BlockHole]s embedded in its DOM.  A [BlockHole] can
 * contain other [Block]s and it is the only way in which DOM can be changed
 * structurally.
 *
 * A [Block] is a collection of DOM nodes and [Directive]s for those nodes.
 *
 * A [Block] is responsible for instantiating the [Directive]s and for
 * inserting / removing itself to/from DOM.
 *
 * A [Block] can be created from [BlockFactory].
 *
 */
class Block implements ElementWrapper {
  List<dom.Node> elements;
  ElementWrapper previous = null;
  ElementWrapper next = null;

  Function onInsert;
  Function onRemove;
  Function onMove;

  List<dynamic> _directives = [];

  Block(List<dom.Node> this.elements);

  Block insertAfter(ElementWrapper previousBlock) {
    // Update Link List.
    next = previousBlock.next;
    if (next != null) {
      next.previous = this;
    }
    previous = previousBlock;
    previousBlock.next = this;

    // Update DOM
    List<dom.Node> previousElements = previousBlock.elements;
    dom.Node previousElement = previousElements[previousElements.length - 1];
    dom.Node insertBeforeElement = previousElement.nextNode;
    dom.Node parentElement = previousElement.parentNode;
    bool preventDefault = false;

    Function insertDomElements = () {
      for(var i = 0, ii = elements.length; i < ii; i++) {
        parentElement.insertBefore(elements[i], insertBeforeElement);
      }
    };

    if (onInsert != null) {
      onInsert({
        "preventDefault": () {
          preventDefault = true;
          return insertDomElements;
        },
        "element": elements[0]
      });
    }

    if (!preventDefault) {
      insertDomElements();
    }
    return this;
  }

  Block remove() {
    bool preventDefault = false;

    Function removeDomElements = () {
      for(var j = 0, jj = elements.length; j < jj; j++) {
        dom.Node current = elements[j];
        dom.Node next = j+1 < jj ? elements[j+1] : null;

        while(next != null && current.nextNode != next) {
          current.nextNode.remove();
        }
        elements[j].remove();
      }
    };

    if (onRemove != null) {
      onRemove({
        "preventDefault": () {
          preventDefault = true;
          return removeDomElements();
        },
        "element": elements[0]
      });
    }

    if (!preventDefault) {
      removeDomElements();
    }

    // Remove block from list
    if (previous != null && (previous.next = next) != null) {
      next.previous = previous;
    }
    next = previous = null;
    return this;
  }

  Block moveAfter(ElementWrapper previousBlock) {
    var previousElements = previousBlock.elements,
        previousElement = previousElements[previousElements.length - 1],
        insertBeforeElement = previousElement.nextNode,
        parentElement = previousElement.parentNode,
        blockElements = elements;

    for(var i = 0, ii = blockElements.length; i < ii; i++) {
      parentElement.insertBefore(blockElements[i], insertBeforeElement);
    }

    // Remove block from list
    previous.next = next;
    if (next != null) {
      next.previous = previous;
    }
    // Add block to list
    next = previousBlock.next;
    if (next != null) {
      next.previous = this;
    }
    previous = previousBlock;
    previousBlock.next = this;
    return this;
  }
}

/**
 * A BlockHole is an instance of a hole. BlockHoles designate where child
 * [Block]s can be added in parent [Block]. BlockHoles wrap a DOM element,
 * and act as references which allows more blocks to be added.
 */

class BlockHole extends ElementWrapper {
  List<dom.Node> elements;

  ElementWrapper previous;

  ElementWrapper next;

  BlockHole(List<dom.Node> this.elements);
}

library dart_code_gen;

import '../../core/parser/parser_library.dart';  // For ParserBackend.
import 'source.dart';

Code VALUE_CODE = new Code("value");

class Code implements ParserAST {
  String id;
  String _exp;
  String simpleGetter;
  Function assign;
  Code(this._exp, [this.assign, this.simpleGetter]) {
    id = _exp == null ? simpleGetter : _exp;
    if (id == null) {
        throw 'id is null';
    }
  }

  get exp {
    if (_exp == null) {
      throw "Can not be used in an expression";
    }
    return _exp;
  }
  get assignable => assign != null;

  Source toSource(SourceBuilder _) {
    return _('new Expression', _.parens(
      _('(scope, [locals])', _.body(
          'return $exp;'
      )),
      assignable ? _('(scope, value, [locals])', _.body(
        'return ${assign(VALUE_CODE).exp};'
      )) : 'null'
    ));
  }
}

class ThrowCode extends Code {
  ThrowCode(code): super('throw $code');
  Source toSource(SourceBuilder _) {
    return _('new Expression', _.parens(
        _('(scope, [locals])', _.body()..source.addAll(exp.split('\n'))),
        assignable ? _('(scope, value, [locals])', _.body()) : 'null'
    ));
  }
}

class MultipleStatementCode extends Code {
  MultipleStatementCode(code): super(code);

  Source toSource(SourceBuilder _) {
    return _('new Expression', _.parens(
        _('(scope, [locals])', _.body()..source.addAll(exp.split('\n'))),
        assignable ? _('(scope, value, [locals])', _.body()) : 'null'
    ));
  }
}

class FilterCode extends Code {
  final String filterName;
  final Code leftHandSide;
  final List<Expression> parameters;
  final Function evalError;

  FilterCode(String this.filterName,
             Code this.leftHandSide,
             List<Code> this.parameters,
             Function this.evalError): super(null);

  get id => '${leftHandSide.id} | $filterName:${parameters.map((e)=>e.id).join(':')}}';

  Source toSource(SourceBuilder _) {
    var params = parameters.map((e) => _.ref(e));
    return _('new FilterExpression', _.parens(
      'filters(${_.str(filterName)})',
      _.ref(leftHandSide),
      '[${params.join(', ')}]'
    ));
  }
}

escape(String s) => s.replaceAll('\'', '\\\'').replaceAll(r'$', r'\$');

class GetterSetterGenerator {
  static RegExp LAST_PATH_PART = new RegExp(r'(.*)\.(.*)');
  static RegExp NON_WORDS = new RegExp(r'\W');

  // From https://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.huusvrzea3q
  static List<String> RESERVED_DART_KEYWORDS = [
      "assert", "break", "case", "catch", "class", "const", "continue",
      "default", "do", "else", "enum", "extends", "false", "final",
      "finally", "for", "if", "in", "is", "new", "null", "rethrow",
      "return", "super", "switch", "this", "throw", "true", "try",
      "var", "void", "while", "with"];
  isReserved(String key) => RESERVED_DART_KEYWORDS.contains(key);


  String functions = "// GETTER AND SETTER FUNCTIONS\n\n";
  var _keyToGetterFnName = {};
  var _keyToSetterFnName = {};
  var nextUid = 0;

  _flatten(key) => key.replaceAll(NON_WORDS, '_');

  fieldGetter(String field, String obj) {
    var eKey = escape(field);

    var returnValue = isReserved(field) ? "undefined_ /* $field is reserved */" : "$obj.$field";

    return """
  if ($obj is Map) {
    if ($obj.containsKey('$eKey')) {
      val = $obj['$eKey'];
    } else {
      val = undefined_;
    }
  } else {
    val = $returnValue;
  }

""";
  }

  fieldSetter(String field, String obj) {
    var eKey = escape(field);

    var maybeField = isReserved(field) ? "/* $field is reserved */" : """
  $obj.$field = value;
  return value;
    """;

    return """
  if ($obj is Map) {
    $obj['$eKey'] = value;
    return value;
  }
  $maybeField
}

""";
  }

  call(String key) {
    if (_keyToGetterFnName.containsKey(key)) {
      return _keyToGetterFnName[key];
    }

    var fnName = "_${_flatten(key)}";

    var keys = key.split('.');
    var lines = [
        "$fnName(s, [l]) { // for $key"];
    _(line) => lines.add('  $line');
    for(var i = 0; i < keys.length; i++) {
      var k = keys[i];
      var sk = isReserved(k) ? "null" : "s.$k";
      if (i == 0) {
        _('if (l != null && l.containsKey("${escape(k)}")) s = l["${escape(k)}"];');
        _('else if (s != null ) s = s is Map ? s["${escape(k)}"] : $sk;');
      } else {
        _('if (s != null ) s = s is Map ? s["${escape(k)}"] : $sk;');
      }
    }
    _('return s;');
    lines.add('}\n\n');

    functions += lines.join('\n');

    _keyToGetterFnName[key] = fnName;
    return fnName;
  }

  setter(String key) {
    if (_keyToSetterFnName.containsKey(key)) {
      return _keyToSetterFnName[key];
    }

    var fnName = "_set_${_flatten(key)}";

    var lines = [
        "$fnName(s, v, [l]) { // for $key"];
    _(line) => lines.add('  $line');
    var keys = key.split('.');
    _(keys.length == 1 ? 'var n = s;' : 'var n;');
    var k = keys[0];
    var sk = isReserved(k) ? "null" : "s.$k";
    var nk = isReserved(k) ? "null" : "n.$k";
    if (keys.length > 1) {
      // locals
      _('if (l != null) n = l["${escape(k)}"];');
      _('if (l == null || (n == null && !l.containsKey("${escape(k)}"))) n = s is Map ? s["${escape(k)}"] : $sk;');
      _('if (n == null) n = s is Map ? (s["${escape(k)}"] = {}) : ($sk = {});');
    }
    for(var i = 1; i < keys.length - 1; i++) {
      k = keys[i];
      sk = isReserved(k) ? "null" : "s.$k";
      nk = isReserved(k) ? "null" : "n.$k";
      // middle
      _('s = n; n = n is Map ? n["${escape(k)}"] : $nk;');
      _('if (n == null) n = s is Map ? (s["${escape(k)}"] = {}) : (${isReserved(k) ? "null" : "$sk = {}"});');
    }
    k = keys[keys.length - 1];
    sk = isReserved(k) ? "null" : "s.$k";
    nk = isReserved(k) ? "null" : "n.$k";
    _('if (n is Map) n["${escape(k)}"] = v; else ${isReserved(k) ? "null" : "$nk = v"};');
    // finish
    _('return v;');
    lines.add('}\n\n');

    functions += lines.join('\n');

    _keyToSetterFnName[key] = fnName;
    return fnName;
  }
}


class DartCodeGen implements ParserBackend {
  static Code ZERO = new Code("0");

  GetterSetterGenerator _getterGen;

  DartCodeGen(GetterSetterGenerator this._getterGen);

  // Returns the Dart code for a particular operator.
  _op(fn) => fn == "undefined" ? "null" : fn;

  Code binaryFn(Code left, String fn, Code right) {
    if (fn == '+') {
      return new Code("autoConvertAdd(${left.exp}, ${right.exp})");
    }
    var leftExp = left.exp;
    var rightExp = right.exp;
    if (fn == '&&' || fn == '||') {
      leftExp = "toBool($leftExp)";
      rightExp = "toBool($rightExp)";
    }
    return new Code("(${leftExp} ${_op(fn)} ${rightExp})");
  }

  Code unaryFn(String fn, Code right) {
    var rightExp = right.exp;
    if (fn == '!') {
      rightExp = "toBool($rightExp)";
    }
    return new Code("${_op(fn)}${rightExp}");
  }

  Code assignment(Code left, Code right, evalError) =>
    left.assign(right);

  Code multipleStatements(List<Code >statements) {
    var code = "var ret, last;\n";
    code += statements.map((Code s) =>
        "last = ${s.exp};\nif (last != null) { ret = last; }\n").join('\n');
    code += "return ret;\n";
    return new MultipleStatementCode(code);
  }

  Code functionCall(Code fn, fnName, List<Code> argsFn, evalError) =>
      new Code("safeFunctionCall(${fn.exp}, \'${escape(fnName)}\', evalError)(${argsFn.map((a) => a.exp).join(', ')})");

  Code arrayDeclaration(List<Code> elementFns) =>
    new Code("[${elementFns.map((Code e) => e.exp).join(', ')}]");

  Code objectIndex(Code obj, Code indexFn, evalError) {
    var assign = (Code right)  =>
        new Code("objectIndexSetField(${obj.exp}, ${indexFn.exp}, ${right.exp}, evalError)");

    return new Code("objectIndexGetField(${obj.exp}, ${indexFn.exp}, evalError)", assign);
  }

  Code fieldAccess(Code object, String field) {
    var getterFnName = _getterGen(field);
    var assign = (Code right) {
      var setterFnName = _getterGen.setter(field);
      return new Code("$setterFnName(${object.exp}, ${right.exp})");
    };
    return new Code("$getterFnName/*field:$field*/(${object.exp}, null)", assign);
  }

  Code object(List keyValues) =>
      new Code(
        "{${keyValues.map((k) => "${_value(k["key"])}: ${k["value"].exp}").join(', ')}}");

  profiled(value, perf, text) => value; // no profiling for now

  Code fromOperator(String op) => new Code(_op(op));

  Code getterSetter(String key) {
    var getterFnName = _getterGen(key);

    var assign = (Code right) {
      var setterFnName = _getterGen.setter(key);
      return new Code("${setterFnName}(scope, ${right.exp}, locals)", null, setterFnName);
    };

    return new Code("$getterFnName(scope, locals)", assign, getterFnName);
  }

  String _value(v) =>
      v is String ? "r\'${escape(v)}\'" : "$v";

  Code value(v) => new Code(_value(v));

  Code zero() => ZERO;

  Code filter(String filterName,
              Code leftHandSide,
              List<Code> parameters,
              Function evalError) {
    return new FilterCode(filterName, leftHandSide, parameters, evalError);
  }
}
// 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.

/**
 * Date/time formatting symbols for all locales.
 *
 * DO NOT EDIT. This file is autogenerated by script.  See
 * http://go/generate_number_constants.py using the --for_dart flag.
 *
 * Before checkin, this file could have been manually edited. This is
 * to incorporate changes before we could correct CLDR. All manual
 * modification must be documented in this section, and should be
 * removed after those changes land to CLDR.
 */

library number_symbol_data;
import "number_symbols.dart";

Map numberFormatSymbols = const {
  /**
   * Number formatting symbols for locale af.
   */
  "af" : const NumberSymbols(
      NAME: "af",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'ZAR'),
  /**
   * Number formatting symbols for locale am.
   */
  "am" : const NumberSymbols(
      NAME: "am",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'ETB'),
  /**
   * Number formatting symbols for locale ar.
   */
  "ar" : const NumberSymbols(
      NAME: "ar",
      DECIMAL_SEP: '\u066B',
      GROUP_SEP: '\u066C',
      PERCENT: '\u066A',
      ZERO_DIGIT: '\u0660',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: '\u0627\u0633',
      PERMILL: '\u0609',
      INFINITY: '\u221E',
      NAN: '\u0644\u064A\u0633\u00A0\u0631\u0642\u0645',
      DECIMAL_PATTERN: '#0.###;#0.###-',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#0.00;\u00A4\u00A0#0.00-',
      DEF_CURRENCY_CODE: 'EGP'),
  /**
   * Number formatting symbols for locale bg.
   */
  "bg" : const NumberSymbols(
      NAME: "bg",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'BGN'),
  /**
   * Number formatting symbols for locale bn.
   */
  "bn" : const NumberSymbols(
      NAME: "bn",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '\u09e6',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u09B8\u0982\u0996\u09CD\u09AF\u09BE\u00A0\u09A8\u09BE',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '#,##,##0.00\u00A4;(#,##,##0.00\u00A4)',
      DEF_CURRENCY_CODE: 'BDT'),
  /**
   * Number formatting symbols for locale ca.
   */
  "ca" : const NumberSymbols(
      NAME: "ca",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale cs.
   */
  "cs" : const NumberSymbols(
      NAME: "cs",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'CZK'),
  /**
   * Number formatting symbols for locale da.
   */
  "da" : const NumberSymbols(
      NAME: "da",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'DKK'),
  /**
   * Number formatting symbols for locale de.
   */
  "de" : const NumberSymbols(
      NAME: "de",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale de_AT.
   */
  "de_AT" : const NumberSymbols(
      NAME: "de_AT",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale de_CH.
   */
  "de_CH" : const NumberSymbols(
      NAME: "de_CH",
      DECIMAL_SEP: '.',
      GROUP_SEP: '\'',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00;\u00A4-#,##0.00',
      DEF_CURRENCY_CODE: 'CHF'),
  /**
   * Number formatting symbols for locale el.
   */
  "el" : const NumberSymbols(
      NAME: "el",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'e',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '[#E0]',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale en.
   */
  "en" : const NumberSymbols(
      NAME: "en",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'USD'),
  /**
   * Number formatting symbols for locale en_AU.
   */
  "en_AU" : const NumberSymbols(
      NAME: "en_AU",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'AUD'),
  /**
   * Number formatting symbols for locale en_GB.
   */
  "en_GB" : const NumberSymbols(
      NAME: "en_GB",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'GBP'),
  /**
   * Number formatting symbols for locale en_IE.
   */
  "en_IE" : const NumberSymbols(
      NAME: "en_IE",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale en_IN.
   */
  "en_IN" : const NumberSymbols(
      NAME: "en_IN",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##,##0.00',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale en_SG.
   */
  "en_SG" : const NumberSymbols(
      NAME: "en_SG",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'SGD'),
  /**
   * Number formatting symbols for locale en_US.
   */
  "en_US" : const NumberSymbols(
      NAME: "en_US",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'USD'),
  /**
   * Number formatting symbols for locale en_ZA.
   */
  "en_ZA" : const NumberSymbols(
      NAME: "en_ZA",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'ZAR'),
  /**
   * Number formatting symbols for locale es.
   */
  "es" : const NumberSymbols(
      NAME: "es",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale es_419.
   */
  "es_419" : const NumberSymbols(
      NAME: "es_419",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'MXN'),
  /**
   * Number formatting symbols for locale et.
   */
  "et" : const NumberSymbols(
      NAME: "et",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#0.00\u00A4;(#0.00\u00A4)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale eu.
   */
  "eu" : const NumberSymbols(
      NAME: "eu",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '%\u00A0#,##0',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4;(#,##0.00\u00A0\u00A4)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale fa.
   */
  "fa" : const NumberSymbols(
      NAME: "fa",
      DECIMAL_SEP: '\u066B',
      GROUP_SEP: '\u066C',
      PERCENT: '\u066A',
      ZERO_DIGIT: '\u06F0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '\u2212',
      EXP_SYMBOL: '\u00D7\u06F1\u06F0^',
      PERMILL: '\u0609',
      INFINITY: '\u221E',
      NAN: '\u0646\u0627\u0639\u062F\u062F',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u200E\u00A4#,##0.00;\u200E(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'IRR'),
  /**
   * Number formatting symbols for locale fi.
   */
  "fi" : const NumberSymbols(
      NAME: "fi",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'ep\u00E4luku',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale fil.
   */
  "fil" : const NumberSymbols(
      NAME: "fil",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'PHP'),
  /**
   * Number formatting symbols for locale fr.
   */
  "fr" : const NumberSymbols(
      NAME: "fr",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4;(#,##0.00\u00A0\u00A4)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale fr_CA.
   */
  "fr_CA" : const NumberSymbols(
      NAME: "fr_CA",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4;(#,##0.00\u00A0\u00A4)',
      DEF_CURRENCY_CODE: 'CAD'),
  /**
   * Number formatting symbols for locale gl.
   */
  "gl" : const NumberSymbols(
      NAME: "gl",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale gsw.
   */
  "gsw" : const NumberSymbols(
      NAME: "gsw",
      DECIMAL_SEP: '.',
      GROUP_SEP: '\u2019',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '\u2212',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'CHF'),
  /**
   * Number formatting symbols for locale gu.
   */
  "gu" : const NumberSymbols(
      NAME: "gu",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale he.
   */
  "he" : const NumberSymbols(
      NAME: "he",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'ILS'),
  /**
   * Number formatting symbols for locale hi.
   */
  "hi" : const NumberSymbols(
      NAME: "hi",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##,##0.00',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale hr.
   */
  "hr" : const NumberSymbols(
      NAME: "hr",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'HRK'),
  /**
   * Number formatting symbols for locale hu.
   */
  "hu" : const NumberSymbols(
      NAME: "hu",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'HUF'),
  /**
   * Number formatting symbols for locale id.
   */
  "id" : const NumberSymbols(
      NAME: "id",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'IDR'),
  /**
   * Number formatting symbols for locale in.
   */
  "in" : const NumberSymbols(
      NAME: "in",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'IDR'),
  /**
   * Number formatting symbols for locale is.
   */
  "is" : const NumberSymbols(
      NAME: "is",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'ISK'),
  /**
   * Number formatting symbols for locale it.
   */
  "it" : const NumberSymbols(
      NAME: "it",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale iw.
   */
  "iw" : const NumberSymbols(
      NAME: "iw",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'ILS'),
  /**
   * Number formatting symbols for locale ja.
   */
  "ja" : const NumberSymbols(
      NAME: "ja",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'JPY'),
  /**
   * Number formatting symbols for locale kn.
   */
  "kn" : const NumberSymbols(
      NAME: "kn",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: '\u0C88',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale ko.
   */
  "ko" : const NumberSymbols(
      NAME: "ko",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'KRW'),
  /**
   * Number formatting symbols for locale ln.
   */
  "ln" : const NumberSymbols(
      NAME: "ln",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'CDF'),
  /**
   * Number formatting symbols for locale lt.
   */
  "lt" : const NumberSymbols(
      NAME: "lt",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '\u2013',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'LTL'),
  /**
   * Number formatting symbols for locale lv.
   */
  "lv" : const NumberSymbols(
      NAME: "lv",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'nav\u00A0skaitlis',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'LVL'),
  /**
   * Number formatting symbols for locale ml.
   */
  "ml" : const NumberSymbols(
      NAME: "ml",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '#,##,##0.00\u00A4',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale mr.
   */
  "mr" : const NumberSymbols(
      NAME: "mr",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale ms.
   */
  "ms" : const NumberSymbols(
      NAME: "ms",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'MYR'),
  /**
   * Number formatting symbols for locale mt.
   */
  "mt" : const NumberSymbols(
      NAME: "mt",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale nl.
   */
  "nl" : const NumberSymbols(
      NAME: "nl",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00;\u00A4\u00A0#,##0.00-',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale no.
   */
  "no" : const NumberSymbols(
      NAME: "no",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
      DEF_CURRENCY_CODE: 'NOK'),
  /**
   * Number formatting symbols for locale or.
   */
  "or" : const NumberSymbols(
      NAME: "or",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##,##0.00',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale pl.
   */
  "pl" : const NumberSymbols(
      NAME: "pl",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4;(#,##0.00\u00A0\u00A4)',
      DEF_CURRENCY_CODE: 'PLN'),
  /**
   * Number formatting symbols for locale pt.
   */
  "pt" : const NumberSymbols(
      NAME: "pt",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'BRL'),
  /**
   * Number formatting symbols for locale pt_BR.
   */
  "pt_BR" : const NumberSymbols(
      NAME: "pt_BR",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'BRL'),
  /**
   * Number formatting symbols for locale pt_PT.
   */
  "pt_PT" : const NumberSymbols(
      NAME: "pt_PT",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale ro.
   */
  "ro" : const NumberSymbols(
      NAME: "ro",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'RON'),
  /**
   * Number formatting symbols for locale ru.
   */
  "ru" : const NumberSymbols(
      NAME: "ru",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u043D\u0435\u00A0\u0447\u0438\u0441\u043B\u043E',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'RUB'),
  /**
   * Number formatting symbols for locale sk.
   */
  "sk" : const NumberSymbols(
      NAME: "sk",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale sl.
   */
  "sl" : const NumberSymbols(
      NAME: "sl",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'e',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'EUR'),
  /**
   * Number formatting symbols for locale sq.
   */
  "sq" : const NumberSymbols(
      NAME: "sq",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'ALL'),
  /**
   * Number formatting symbols for locale sr.
   */
  "sr" : const NumberSymbols(
      NAME: "sr",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'RSD'),
  /**
   * Number formatting symbols for locale sv.
   */
  "sv" : const NumberSymbols(
      NAME: "sv",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '\u2212',
      EXP_SYMBOL: '\u00D710^',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u00A4\u00A4\u00A4',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0\u00A0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'SEK'),
  /**
   * Number formatting symbols for locale sw.
   */
  "sw" : const NumberSymbols(
      NAME: "sw",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'TZS'),
  /**
   * Number formatting symbols for locale ta.
   */
  "ta" : const NumberSymbols(
      NAME: "ta",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##,##0%',
      CURRENCY_PATTERN: '\u00A4\u00A0#,##,##0.00',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale te.
   */
  "te" : const NumberSymbols(
      NAME: "te",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'INR'),
  /**
   * Number formatting symbols for locale th.
   */
  "th" : const NumberSymbols(
      NAME: "th",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'THB'),
  /**
   * Number formatting symbols for locale tl.
   */
  "tl" : const NumberSymbols(
      NAME: "tl",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'PHP'),
  /**
   * Number formatting symbols for locale tr.
   */
  "tr" : const NumberSymbols(
      NAME: "tr",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '%#,##0',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4;(#,##0.00\u00A0\u00A4)',
      DEF_CURRENCY_CODE: 'TRY'),
  /**
   * Number formatting symbols for locale uk.
   */
  "uk" : const NumberSymbols(
      NAME: "uk",
      DECIMAL_SEP: ',',
      GROUP_SEP: '\u00A0',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: '\u0415',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u041D\u0435\u00A0\u0447\u0438\u0441\u043B\u043E',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'UAH'),
  /**
   * Number formatting symbols for locale ur.
   */
  "ur" : const NumberSymbols(
      NAME: "ur",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'PKR'),
  /**
   * Number formatting symbols for locale vi.
   */
  "vi" : const NumberSymbols(
      NAME: "vi",
      DECIMAL_SEP: ',',
      GROUP_SEP: '.',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
      DEF_CURRENCY_CODE: 'VND'),
  /**
   * Number formatting symbols for locale zh.
   */
  "zh" : const NumberSymbols(
      NAME: "zh",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'CNY'),
  /**
   * Number formatting symbols for locale zh_CN.
   */
  "zh_CN" : const NumberSymbols(
      NAME: "zh_CN",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'CNY'),
  /**
   * Number formatting symbols for locale zh_HK.
   */
  "zh_HK" : const NumberSymbols(
      NAME: "zh_HK",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u975E\u6578\u503C',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'HKD'),
  /**
   * Number formatting symbols for locale zh_TW.
   */
  "zh_TW" : const NumberSymbols(
      NAME: "zh_TW",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: '\u975E\u6578\u503C',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00',
      DEF_CURRENCY_CODE: 'TWD'),
  /**
   * Number formatting symbols for locale zu.
   */
  "zu" : const NumberSymbols(
      NAME: "zu",
      DECIMAL_SEP: '.',
      GROUP_SEP: ',',
      PERCENT: '%',
      ZERO_DIGIT: '0',
      PLUS_SIGN: '+',
      MINUS_SIGN: '-',
      EXP_SYMBOL: 'E',
      PERMILL: '\u2030',
      INFINITY: '\u221E',
      NAN: 'I-NaN',
      DECIMAL_PATTERN: '#,##0.###',
      SCIENTIFIC_PATTERN: '#E0',
      PERCENT_PATTERN: '#,##0%',
      CURRENCY_PATTERN: '\u00A4#,##0.00;(\u00A4#,##0.00)',
      DEF_CURRENCY_CODE: 'ZAR')
};
// 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 number_symbols;

/**
 * This holds onto information about how a particular locale formats numbers. It
 * contains strings for things like the decimal separator, digit to use for "0"
 * and infinity. We expect the data for instances to be generated out of ICU
 * or a similar reference source.
 */
class NumberSymbols {
  final String NAME;
  final String DECIMAL_SEP, GROUP_SEP, PERCENT, ZERO_DIGIT, PLUS_SIGN,
      MINUS_SIGN, EXP_SYMBOL, PERMILL, INFINITY, NAN, DECIMAL_PATTERN,
      SCIENTIFIC_PATTERN, PERCENT_PATTERN, CURRENCY_PATTERN, DEF_CURRENCY_CODE;

  const NumberSymbols({this.NAME,
                       this.DECIMAL_SEP,
                       this.GROUP_SEP,
                       this.PERCENT,
                       this.ZERO_DIGIT,
                       this.PLUS_SIGN,
                       this.MINUS_SIGN,
                       this.EXP_SYMBOL,
                       this.PERMILL,
                       this.INFINITY,
                       this.NAN,
                       this.DECIMAL_PATTERN,
                       this.SCIENTIFIC_PATTERN,
                       this.PERCENT_PATTERN,
                       this.CURRENCY_PATTERN,
                       this.DEF_CURRENCY_CODE});

  toString() => NAME;
}
part of angular.directive;

/**
 * The `ngCloak` directive is used to prevent the Angular html template from
 * being briefly displayed by the browser in its raw (uncompiled) form while
 * your application is loading. Use this directive to avoid the undesirable
 * flicker effect caused by the html template display.
 *
 * The directive can be applied to the `<body>` element, but typically a
 * fine-grained application is preferred in order to benefit from progressive
 * rendering of the browser view.
 *
 * `ngCloak` works in cooperation with a css. Following is the css rule:
 *
 *     [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
 *        display: none !important;
 *     }
 *
 * When this css rule is loaded by the browser, all html elements (including
 * their children) that are tagged with the `ng-cloak` directive are hidden.
 * When Angular comes across this directive during the compilation of the
 * template it deletes the `ngCloak` element attribute, which makes the compiled
 * element visible.
 */
@NgDirective(selector: '[ng-cloak]')
@NgDirective(selector: '.ng-cloak')
class NgCloakDirective {
  NgCloakDirective(dom.Element element) {
    element.attributes.remove('ng-cloak');
    element.classes.remove('ng-cloak');
  }
}
library di.dynamic_injector;

import 'mirrors.dart';
import 'errors.dart';
import 'module.dart';
import 'injector.dart';

/**
 * Dynamic implementation of [Injector] that uses mirrors.
 */
class DynamicInjector implements Injector {
  final bool allowImplicitInjection;
  final String name;

  final DynamicInjector parent;

  final Map<Symbol, _ProviderMetadata> providers =
      new Map<Symbol, _ProviderMetadata>();
  final Map<Symbol, Object> instances = new Map<Symbol, Object>();

  final List<Symbol> resolving = new List<Symbol>();

  final List<Type> _types = [];

  DynamicInjector({List<Module> modules, String name,
                   bool allowImplicitInjection: false})
      : this._fromParent(modules, null, name: name,
                         allowImplicitInjection: allowImplicitInjection);

  DynamicInjector._fromParent(List<Module> modules, Injector this.parent,
      {bool this.allowImplicitInjection: false, this.name}) {
    if (modules == null) {
      modules = <Module>[];
    }
    modules.forEach((module) {
      module.bindings.forEach(_registerBinding);
    });
    _registerBinding(Injector, new ValueBinding(this));
  }

  _registerBinding(Type type, Binding binding) {
    this._types.add(type);
    var symbol = getTypeSymbol(type);
    if (binding is ValueBinding) {
      providers[symbol] = new _ProviderMetadata.forValue(binding);
    } else if (binding is TypeBinding) {
      providers[symbol] = new _ProviderMetadata.forType(binding);
    } else if (binding is FactoryBinding) {
      providers[symbol] = new _ProviderMetadata.forFactory(binding);
    } else {
      throw 'Unknown binding type ${binding.runtimeType}';
    }
  }

  Set<Type> get types {
    var types = new Set.from(_types);
    var parent = this.parent;
    while (parent != null) {
      for(var type in parent._types) {
        if (!types.contains(type)) {
          types.add(type);
        }
      }
      parent = parent.parent;
    }
    return types;
  }

  String _error(message, [appendDependency]) {
    if (appendDependency != null) {
      resolving.add(appendDependency);
    }

    String graph = resolving.map(getSymbolSimpleName).join(' -> ');

    resolving.clear();

    return '$message (resolving $graph)';
  }

  dynamic _getInstanceBySymbol(Symbol typeName, Injector requester) {
    _checkTypeConditions(typeName);

    if (resolving.contains(typeName)) {
      throw new CircularDependencyError(
          _error('Cannot resolve a circular dependency!', typeName));
    }

    var providerWithInjector = _getProviderForSymbol(typeName);
    var metadata = providerWithInjector.providerMetadata;
    var visible =
        metadata.binding.visibility(requester, providerWithInjector.injector);

    if (visible && instances.containsKey(typeName)) {
      return instances[typeName];
    }

    if (providerWithInjector.injector != this || !visible) {
      var injector = providerWithInjector.injector;
      if (!visible) {
        injector = providerWithInjector.injector.parent.
            _getProviderForSymbol(typeName).injector;
      }
      return injector._getInstanceBySymbol(typeName, requester);
    }

    var getInstanceBySymbol =
        _wrapGetInstanceBySymbol(_getInstanceBySymbol, requester);
    var value;
    try {
      value = metadata.binding.creationStrategy(requester,
          providerWithInjector.injector, () {
        resolving.add(typeName);
        var val = metadata.provider.get(getInstanceBySymbol, _error);
        resolving.removeLast();
        return val;
      });
    } catch(e) {
      resolving.clear();
      rethrow;
    }

    // cache the value.
    providerWithInjector.injector.instances[typeName] = value;
    return value;
  }

  /**
   *  Wraps getInstanceBySymbol function with a requster value to be easily
   *  down to the providers.
   */
  ObjectFactory _wrapGetInstanceBySymbol(Function getInstanceBySymbol,
                                    Injector requester) {
    return (Symbol typeName) {
      return getInstanceBySymbol(typeName, requester);
    };
  }

  /// Returns a pair for provider and the injector where it's defined.
  _ProviderWithDefiningInjector _getProviderForSymbol(Symbol typeName) {
    if (providers.containsKey(typeName)) {
      return new _ProviderWithDefiningInjector(providers[typeName], this);
    }

    if (parent != null) {
      return parent._getProviderForSymbol(typeName);
    }

    if (!allowImplicitInjection) {
      throw new NoProviderError(_error('No provider found for '
          '${getSymbolSimpleName(typeName)}!', typeName));
    }

    // create a provider for implicit types
    return new _ProviderWithDefiningInjector(
        new _ProviderMetadata.forSymbol(typeName), this);
  }

  void _checkTypeConditions(Symbol typeName) {
    if (PRIMITIVE_TYPES.contains(typeName)) {
      throw new NoProviderError(_error('Cannot inject a primitive type '
          'of ${getSymbolSimpleName(typeName)}!', typeName));
    }
  }


  // PUBLIC API

  /**
   * Get an instance for given token ([Type]).
   *
   * If the injector already has an instance for this token, it returns this
   * instance. Otherwise, injector resolves all its dependencies, instantiate
   * new instance and returns this instance.
   *
   * If there is no binding for given token, injector asks parent injector.
   *
   * If there is no parent injector, an implicit binding is used. That is,
   * the token ([Type]) is instantiated.
   */
  dynamic get(Type type) =>
      _getInstanceBySymbol(getTypeSymbol(type), this);

  /**
   * Invoke given function and inject all its arguments.
   *
   * Returns whatever the function returns.
   */
  dynamic invoke(Function fn) {
    ClosureMirror cm = reflect(fn);
    MethodMirror mm = cm.function;
    num position = 0;
    List args = mm.parameters.map((ParameterMirror parameter) {
      try {
        return _getInstanceBySymbol(parameter.type.qualifiedName, this);
      } on NoProviderError catch (e) {
        throw new NoProviderError(e.message + ' at position $position source:\n ${mm.source}.');
      } finally {
        position++;
      }
    }).toList();

    try {
      return cm.apply(args, null).reflectee;
    } catch (e) {
      if (e is MirroredUncaughtExceptionError) {
        throw "${e}\nORIGINAL STACKTRACE\n${(e as MirroredUncaughtExceptionError).stacktrace}";
      }
      rethrow;
    }
  }

  /**
   * Create a child injector.
   *
   * Child injector can override any bindings by adding additional modules.
   *
   * It also accepts a list of tokens that a new instance should be forced.
   * That means, even if some parent injector already has an instance for this
   * token, there will be a new instance created in the child injector.
   */
  Injector createChild(List<Module> modules,
                       {List<Type> forceNewInstances, String name}) {
    if (forceNewInstances != null) {
      Module forceNew = new Module();
      forceNewInstances.forEach((Type type) {
        var providerWithInjector = _getProviderForSymbol(getTypeSymbol(type));
        var metadata = providerWithInjector.providerMetadata;
        forceNew.factory(type,
            (DynamicInjector inj) => metadata.provider.get(
                _wrapGetInstanceBySymbol(inj._getInstanceBySymbol, inj),
                inj._error),
            creation: metadata.binding.creationStrategy,
            visibility: metadata.binding.visibility);
      });

      modules = modules.toList(); // clone
      modules.add(forceNew);
    }

    return new DynamicInjector._fromParent(modules, this, name: name);
  }
}

class _ProviderWithDefiningInjector {
  final _ProviderMetadata providerMetadata;
  final DynamicInjector injector;
  _ProviderWithDefiningInjector(this.providerMetadata, this.injector);
}

typedef Object ObjectFactory(Symbol symbol);

abstract class _Provider {
  dynamic get(ObjectFactory getInstanceBySymbol, error);
}

class _ValueProvider implements _Provider {
  dynamic value;

  _ValueProvider(value) {
    this.value = value;
  }

  dynamic get(getInstanceBySymbol, error) {
    return value;
  }
}


class _TypeProvider implements _Provider {
  final ClassMirror classMirror;
  final Symbol typeName;

  _TypeProvider(Symbol typeName)
      : this.typeName = typeName,
        this.classMirror = getClassMirrorBySymbol(typeName);

  dynamic get(getInstanceBySymbol, error) {

    if (classMirror is TypedefMirror) {
      throw new NoProviderError(error('No implementation provided '
          'for ${getSymbolName(classMirror.qualifiedName)} typedef!'));
    }

    MethodMirror ctor = classMirror.constructors[classMirror.simpleName];

    resolveArgument(int pos) {
      ParameterMirror p = ctor.parameters[pos];
      try {
        return getInstanceBySymbol(p.type.qualifiedName);
      } on NoProviderError catch (e) {
        throw new NoProviderError(e.message + ' at position $pos source:\n ${ctor.source}.');
      }
    }

    var args = new List.generate(ctor.parameters.length, resolveArgument,
        growable: false);
    return classMirror.newInstance(ctor.constructorName, args).reflectee;
  }
}


class _FactoryProvider implements _Provider {
  final Function factoryFn;

  _FactoryProvider(Function this.factoryFn);

  dynamic get(getInstanceBySymbol, error) {
    return Function.apply(factoryFn,
        [getInstanceBySymbol(getTypeSymbol(Injector))]);
  }
}

class _ProviderMetadata {
  _Provider provider;
  Binding binding;

  _ProviderMetadata.forValue(ValueBinding binding) {
    provider = new _ValueProvider(binding.value);
    this.binding = binding;
  }

  _ProviderMetadata.forType(TypeBinding binding) {
    provider = new _TypeProvider(getTypeSymbol(binding.type));
    this.binding = binding;
  }

  _ProviderMetadata.forSymbol(Symbol symbol) {
    provider = new _TypeProvider(symbol);
    this.binding = new TypeBinding(null);
  }

  _ProviderMetadata.forFactory(FactoryBinding binding) {
    provider = new _FactoryProvider(binding.factoryFn);
    this.binding = binding;
  }
}
part of angular.directive;

@NgDirective(
    selector: '[ng-include]',
    map: const {'ng-include': '=.url'} )
class NgIncludeDirective {

  dom.Element element;
  Scope scope;
  BlockCache blockCache;
  Injector injector;

  Block _previousBlock;
  Scope _previousScope;

  NgIncludeDirective(dom.Element this.element,
                         Scope this.scope,
                         BlockCache this.blockCache,
                         Injector this.injector);

  _cleanUp() {
    if (_previousBlock == null) {
      return;
    }

    _previousBlock.remove();
    _previousScope.$destroy();
    element.innerHtml = '';

    _previousBlock = null;
    _previousScope = null;
  }

  _updateContent(createBlock) {
    _cleanUp();

    // create a new scope
    _previousScope = scope.$new();
    _previousBlock = createBlock(injector.createChild([new Module()..value(Scope, _previousScope)]));

    _previousBlock.elements.forEach((elm) => element.append(elm));
  }


  set url(value) {
    if (value == null || value == '') {
      _cleanUp();
      return;
    }

    if (value.startsWith('<')) {
      // inlined template
      _updateContent(blockCache.fromHtml(value));
    } else {
      // an url template
      blockCache.fromUrl(value).then((createBlock) => _updateContent(createBlock));
    }
  }
}
library angular.directive;

import 'package:di/di.dart';
import 'dart:html' as dom;
import 'dart:async' as async;
import '../core/module.dart';
import '../core/parser/parser_library.dart';
import '../core_dom/module.dart';
import '../utils.dart';

part 'ng_a.dart';
part 'ng_bind.dart';
part 'ng_bind_html.dart';
part 'ng_bind_template.dart';
part 'ng_class.dart';
part 'ng_events.dart';
part 'ng_cloak.dart';
part 'ng_if.dart';
part 'ng_include.dart';
part 'ng_model.dart';
part 'ng_repeat.dart';
part 'ng_template.dart';
part 'ng_show_hide.dart';
part 'ng_src_boolean.dart';
part 'ng_style.dart';
part 'ng_switch.dart';
part 'ng_non_bindable.dart';
part 'input_select.dart';

class NgDirectiveModule extends Module {
  NgDirectiveModule() {
    value(NgADirective, null);
    value(NgBindDirective, null);
    value(NgBindTemplateDirective, null);
    value(NgBindHtmlDirective, null);
    value(NgClassDirective, null);
    value(NgClassOddDirective, null);
    value(NgClassEvenDirective, null);
    value(NgCloakDirective, null);
    value(NgHideDirective, null);
    value(NgIfDirective, null);
    value(NgUnlessDirective, null);
    value(NgIncludeDirective, null);
    value(NgRepeatDirective, null);
    value(NgShowDirective, null);
    value(InputTextDirective, null);
    value(InputCheckboxDirective, null);
    value(InputSelectDirective, null);
    value(OptionValueDirective, null);
    value(NgModel, null);
    value(NgSwitchDirective, null);
    value(NgSwitchWhenDirective, null);
    value(NgSwitchDefaultDirective, null);

    value(NgBooleanAttributeDirective, null);
    value(NgSourceDirective, null);

    value(NgEventDirective, null);
    value(NgStyleDirective, null);
    value(NgNonBindableDirective, null);
    value(NgTemplateDirective, null);
  }
}
import 'package:angular/core/parser/parser_library.dart';

class _AST implements ParserAST {
  bool get assignable => true;
}

class DartGetterSetterGen implements ParserBackend {
  Map<String, bool> identifiers = {};

  profiled(value, perf, text)  => new _AST();

  binaryFn(left, String fn, right) => new _AST();
  unaryFn(String fn, right)  => new _AST();
  assignment(left, right, evalError)  => new _AST();
  multipleStatements(List statements)  => new _AST();
  arrayDeclaration(List elementFns)  => new _AST();
  objectIndex(obj, indexFn, evalError)  => new _AST();
  object(List keyValues)  => new _AST();
  fromOperator(String op) => new _AST();
  value(v) => new _AST();
  zero() => new _AST();
  functionCall(fn, fnName, List argsFn, evalError) => new _AST();


  fieldAccess(object, String field) {
    identifiers[field] = true;
    return new _AST();
  }

  getterSetter(String key)  {
    key.split('.').forEach((i) => identifiers[i] = true);
    return new _AST();
  }
}

class ParserGetterSetter {

  DynamicParser parser;
  DartGetterSetterGen backend;

  ParserGetterSetter(DynamicParser this.parser, ParserBackend this.backend);

  generateParser(List<String> exprs) {
    exprs.forEach((expr) {
      try {
        parser(expr);
      } catch (e) { }
    });

    print(generateCode(backend.identifiers.keys.toList()));
  }

  generateCode(List<String> keys) {
    return '''
class StaticGetterSetter extends GetterSetter {
  Map<String, Function> _getters = ${generateGetterMap(keys)};
  Map<String, Function> _setters = ${generateSetterMap(keys)};

  Function getter(String key) {
    return _getters.containsKey(key) ? _getters[key] : super.getter(key);
  }

  Function setter(String key) {
    return _setters.containsKey(key) ? _setters[key] : super.setter(key);
  }

}
''';
  }

  generateGetterMap(List<String> keys) {
    var lines = keys.map((key) => 'r"${key}": (s) => s.$key');
    return '{\n   ${lines.join(",\n    ")}\n  }';
  }

  generateSetterMap(List<String> keys) {
    var lines = keys.map((key) => 'r"${key}": (s, v) => s.$key = v');
    return '{\n   ${lines.join(",\n    ")}\n  }';
  }
}
part of angular.mock;

/**
 * Class which simplifies bootstraping of angular for unit tests.
 *
 * Simply inject [TestBed] into the test, then use [compile] to
 * match directives against the view.
 */
class TestBed {
  final Injector injector;
  final Scope rootScope;
  final Compiler compiler;
  final Parser parser;


  Element rootElement;
  List<Node> rootElements;
  Block rootBlock;

  TestBed(
      Injector this.injector,
      Scope this.rootScope,
      Compiler this.compiler,
      Parser this.parser);


  /**
   * Use to compile HTML and activete its directives.
   *
   * If [html] parametr is:
   *
   *   - [String] then treat it as HTML
   *   - [Node] then treat it as the root node
   *   - [List<Node>] then treat it as a collection of nodse
   *
   * After the compilation the [rootElements] contains an array of compiled root nodes,
   * and [rootElement] contains the first element from the [rootElemets].
   *
   */
  Element compile(html) {
    if (html is String) {
      rootElements = toNodeList(html);
    } else if (html is Node) {
      rootElements = [html];
    } else if (html is List<Node>) {
      rootElements = html;
    } else {
      throw 'Expecting: String, Node, or List<Node> got $html.';
    }
    rootElement = rootElements[0];
    rootBlock = compiler(rootElements)(injector, rootElements);
    return rootElement;
  }

  /**
   * Convert an [html] String to a [List] of [Element]s.
   */
  List<Element> toNodeList(html) {
    var div = new DivElement();
    div.setInnerHtml(html, treeSanitizer: new NullTreeSanitizer());
    var nodes = [];
    for(var node in div.nodes) {
      nodes.add(node);
    }
    return nodes;
  }

  /**
   * Triggern a specific DOM element on a given node to test directives
   * which listen to events.
   */
  triggerEvent(element, name, [type='MouseEvent']) {
    element.dispatchEvent(new Event.eventType(type, name));
  }

  /**
   * Select an [OPTION] in a [SELECT] with a given name and trigger the
   * appropriate DOM event. Used when testing [SELECT] controlls in forms.
   */
  selectOption(element, text) {
    element.queryAll('option').forEach((o) => o.selected = o.text == text);
    triggerEvent(element, 'change');
  }
}
part of angular.core.dom;

class UrlRewriter {
  String call(url) => url;
}

/**
 * HTTP backend used by the [Http] service that delegates to dart:html's
 * [HttpRequest] and deals with Dart bugs.
 *
 * Never use this service directly, instead use the higher-level [Http].
 *
 * During testing this implementation is swapped with [MockHttpBackend] which
 * can be trained with responses.
 */
class HttpBackend {
  /**
   * Wrapper around dart:html's [HttpRequest.request]
   */
  async.Future request(String url,
      {String method, bool withCredentials, String responseType,
      String mimeType, Map<String, String> requestHeaders, sendData,
      void onProgress(dom.ProgressEvent e)}) {
    // Complete inside a then to work-around dartbug.com/13051
    var c = new async.Completer();

    dom.HttpRequest.request(url,
        method: method,
        withCredentials: withCredentials,
        responseType: responseType,
        mimeType: mimeType,
        requestHeaders: requestHeaders,
        sendData: sendData,
        onProgress: onProgress).then((x) => c.complete(x));
    return c.future;
  }
}

typedef RequestInterceptor(HttpResponseConfig);
typedef RequestErrorInterceptor(dynamic);
typedef Response(HttpResponse);
typedef ResponseError(dynamic);

/**
* HttpInterceptors are used to modify the Http request.  They can be added to
* [HttpInterceptors] or passed into [Http.call].
*/
class HttpInterceptor {
  RequestInterceptor request;
  Response response;
  RequestErrorInterceptor requestError;
  ResponseError responseError;

  /**
   * All parameters are optional.
   */
  HttpInterceptor({
      this.request, this.response,
      this.requestError, this.responseError});
}


/**
* The default transform data interceptor.abstract
*
* For requests, this interceptor will
* automatically stringify any non-string non-file objects.
*
* For responses, this interceptor will unwrap JSON objects and
* parse them into [Map]s.
*/
class DefaultTransformDataHttpInterceptor implements HttpInterceptor {
  Function request = (HttpResponseConfig config) {
    if (config.data != null && config.data is! String && config.data is! dom.File) {
      config.data = json.stringify(config.data);
    }
    return config;
  };

  static var _JSON_START = new RegExp(r'^\s*(\[|\{[^\{])');
  static var _JSON_END = new RegExp(r'[\}\]]\s*$');
  static var _PROTECTION_PREFIX = new RegExp('^\\)\\]\\}\',?\\n');
  Function response = (HttpResponse r) {
    if (r.data is String) {
      var d = r.data;
      d = d.replaceFirst(_PROTECTION_PREFIX, '');
      if (d.contains(_JSON_START) && d.contains(_JSON_END)) {
        d = json.parse(d);
      }
      return new HttpResponse.copy(r, data: d);
    }
    return r;
  };

  Function requestError, responseError;

}

/**
 * A list of [HttpInterceptor]s.
 */
class HttpInterceptors {
  List<HttpInterceptor> _interceptors = [new DefaultTransformDataHttpInterceptor()];

  add(HttpInterceptor x) => _interceptors.add(x);
  addAll(List<HttpInterceptor> x) => _interceptors.addAll(x);

  /**
   * Called from [Http] to construct a [Future] chain.
   */
  constructChain(List chain) {
    _interceptors.reversed.forEach((HttpInterceptor i) {
      // AngularJS has an optimization of not including null interceptors.
      chain.insert(0, [
          i.request == null ? (x) => x : i.request,
          i.requestError]);
      chain.add([
          i.response == null ? (x) => x : i.response,
          i.responseError]);
    });
  }

 /**
   * Default constructor.
   */
  HttpInterceptors() {
    _interceptors = [new DefaultTransformDataHttpInterceptor()];
  }

  /**
   * Creates a [HttpInterceptors] from a [List].  Does not include the default interceptors.
   */
  HttpInterceptors.of([List interceptors]) {
    _interceptors = interceptors;
  }
}

/**
 * The request configuration of the request associated with this response.
 */
class HttpResponseConfig {
  /**
   * The request's URL
   */
  String url;

  /**
   * The request params as a Map
   */
  Map params;

  /**
   * The header map without mangled keys
   */
  Map headers;

  var data;


  var _headersObj;

  /**
   * Header accessor.  Given a string, it will return the matching header,
   * case-insentivitively.  Without a string, returns a header object will
   * upper-case keys.
   */
  header([String name]) {
    if (_headersObj == null) {
      _headersObj = {};
      headers.forEach((k,v) {
        _headersObj[k.toLowerCase()] = v;
      });
    }

    if (name != null) {
      name = name.toLowerCase();
      if (!_headersObj.containsKey(name)) return null;
      return _headersObj[name];
    }

    return _headersObj;
  }

  /**
   * Constructor
   */
  HttpResponseConfig({this.url, this.params, this.headers, this.data});
}

/**
 * The response for an HTTP request.  Returned from the [Http] service.
 */
class HttpResponse {
  /**
   * The HTTP status code.
   */
  int status;

  /**
   * DEPRECATED
   */
  var responseText;
  Map _headers;

  /**
   * The [HttpResponseConfig] object which contains the requested URL
   */
  HttpResponseConfig config;

  /**
   * Constructor
   */
  HttpResponse([this.status, this.responseText, this._headers, this.config]);

  /**
   * Copy constructor.  Creates a clone of the response, optionally with new
   * data.
   */
  HttpResponse.copy(HttpResponse r, {data}) {
    status = r.status;
    responseText = data == null ? r.responseText : data;
    _headers = r._headers == null ? null : new Map.from(r._headers);
    config = r.config;
  }

  /**
   * The response's data.  Either a string or a transformed object.
   */
  get data => responseText;

  /**
   * The response's headers.  Without parameters, this method will return the
   * [Map] of headers.  With [key] parameter, this method will return the specific
   * header.
   */
  headers([String key]) {
    if (key == null) {
      return _headers;
    }
    if (_headers.containsKey(key)) {
      return _headers[key];
    }
    return null;
  }

  /**
   * Useful for debugging.
   */
  toString() => 'HTTP $status: $data';
}

/**
 * Default header configuration.
 */
class HttpDefaultHeaders {
  static String _defaultContentType = 'application/json;charset=utf-8';
  Map _headers = {
    'COMMON': {
        'Accept': 'application/json, text/plain, */*'
    },
    'POST' : {
        'Content-Type': _defaultContentType
    },
    'PUT' : {
      'Content-Type': _defaultContentType
    },
    'PATCH' : {
      'Content-Type': _defaultContentType
    }
  };

  _applyHeaders(method, ucHeaders, headers) {
    if (!_headers.containsKey(method)) return;
    _headers[method].forEach((k, v) {
      if (!ucHeaders.contains(k.toUpperCase())) {
        headers[k] = v;
      }
    });
  }

  /**
   * Called from [Http], this method sets default headers on [headers]
   */
  setHeaders(Map<String, String> headers, String method) {
    assert(headers != null);
    var ucHeaders = headers.keys.map((x) => x.toUpperCase()).toSet();
    _applyHeaders('COMMON', ucHeaders, headers);
    _applyHeaders(method.toUpperCase(), ucHeaders, headers);
  }

  /**
   * Returns the default header [Map] for a method.  You can then modify
   * the map.
   *
   * Passing 'common' as [method] will return a Map that contains headers
   * common to all operations.
   */
  operator[](method) {
    return _headers[method.toUpperCase()];
  }
}

/**
* Injected into the [Http] service.  This class contains application-wide
* HTTP defaults.
*
* The default implementation provides headers which the
* Angular team believes to be useful.
*/
class HttpDefaults {
  /**
   * The [HttpDefaultHeaders] object used by [Http] to add default headers
   * to requests.
   */
  HttpDefaultHeaders headers;

  /**
   * The default cache.  To enable caching application-wide, instantiate with a
   * [Cache] object.
   */
  var cache;

  /**
   * Constructor intended for DI.
   */
  HttpDefaults(HttpDefaultHeaders this.headers);
}

/**
 * The [Http] service facilitates communication with the remote HTTP servers.  It
 * uses dart:html's [HttpRequest] and provides a number of features on top
 * of the core Dart library.
 *
 * For unit testing, applications should use the [MockHttpBackend] service.
 *
 * # General usage
 * The [call] method takes a number of named parameters and returns a
 * [Future<HttpResponse>].
 *
 *      http(method: 'GET', url: '/someUrl')
 *        .then((HttpResponse response) { .. },
 *               onError: (HttpRequest request) { .. });
 *
 * A response status code between 200 and 299 is considered a success status and
 * will result in the 'then' being called. Note that if the response is a redirect,
 * Dart's [HttpRequest] will transparently follow it, meaning that the error callback will not be
 * called for such responses.
 *
 * # Shortcut methods
 *
 * The Http service also defines a number of shortcuts:
 *
 *      http.get('/someUrl') is the same as http(method: 'GET', url: '/someUrl')
 *
 * See the method definitions below.
 *
 * # Setting HTTP Headers
 *
 * The [Http] service will add certain HTTP headers to requests.  These defaults
 * can be configured using the [HttpDefaultHeaders] object.  The defaults are:
 *
 * - For all requests: `Accept: application/json, text/plain, * / *`
 * - For POST, PUT, PATCH requests: `Content-Type: application/json`
 *
 * # Caching
 *
 * To enable caching, pass a [Cache] object into the [call] method.  The [Http]
 * service will store responses in the cache and return the response for
 * any matching requests.
 *
 * Note that data is returned through a [Future], regardless of whether it
 * came from the [Cache] or the server.
 *
 * If there are multiple GET requests for the same not-yet-in-cache URL
 * while a cache is in use, only one request to the server will be made.
 *
 * # Interceptors
 *
 * Http uses the interceptors from [HttpInterceptors]. You can also include
 * interceptors in the [call] method.
 *
 * # Security Considerations
 *
 * NOTE: < not yet documented >
 */
class Http {
  Map<String, async.Future<HttpResponse>> _pendingRequests = <String, async.Future<HttpResponse>>{};
  UrlRewriter _rewriter;
  HttpBackend _backend;
  HttpInterceptors _interceptors;

  /**
   * The defaults for [Http]
   */
  HttpDefaults defaults;

  /**
   * Constructor, useful for DI.
   */
  Http(UrlRewriter this._rewriter,
       HttpBackend this._backend,
       HttpDefaults this.defaults,
       HttpInterceptors this._interceptors);

  /**
   * DEPRECATED
   */
  async.Future<String> getString(String url,
      {bool withCredentials, void onProgress(dom.ProgressEvent e), Cache cache}) {
    return request(url,
        withCredentials: withCredentials,
        onProgress: onProgress,
        cache: cache).then((HttpResponse xhr) => xhr.responseText);
  }

/**
  * Returns a [Future<HttpResponse>] when the request is fulfilled.
  *
  * Named Parameters:
  * - method: HTTP method (e.g. 'GET', 'POST', etc)
  * - url: Absolute or relative URL of the resource being requested.
  * - data: Data to be sent as the request message data.
  * - params: Map of strings or objects which will be turned to
  *          `?key1=value1&key2=value2` after the url. If the values are
  *           not strings, they will be JSONified.
  * - headers: Map of strings or functions which return strings representing
  *      HTTP headers to send to the server. If the return value of a function
  *      is null, the header will not be sent.
  * - xsrfHeaderName: TBI
  * - xsrfCookieName: TBI
  * - interceptors: Either a [HttpInterceptor] or a [HttpInterceptors]
  * - cache: Boolean or [Cache].  If true, the default cache will be used.
  * - timeout: deprecated
*/
  async.Future<HttpResponse> call({
    String url,
    String method,
    data,
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) {
    if (xsrfHeaderName != null || xsrfCookieName != null ||
        timeout != null) {
      throw ['not implemented'];
    }

    method = method.toUpperCase();

    if (headers == null) { headers = {}; }
    defaults.headers.setHeaders(headers, method);

    // Check for functions in headers
    headers.forEach((k,v) {
      if (v is Function) {
        headers[k] = v();
      }
    });

    var serverRequest = (HttpResponseConfig config) {
      assert(config.data == null || config.data is String || config.data is dom.File);

      // Strip content-type if data is undefined
      if (config.data == null) {
        List<String> toRemove = [];
        headers.forEach((h, _) {
          if (h.toUpperCase() == 'CONTENT-TYPE') {
            toRemove.add(h);
          };
        });
        toRemove.forEach((x) => headers.remove(x));
      }


      return request(
          null,
          config: config,
          method: method,
          sendData: config.data,
          requestHeaders: config.headers,
          cache: cache);
    };

    var chain = [[serverRequest, null]];

    var future = new async.Future.value(new HttpResponseConfig(
        url: url,
        params: params,
        headers: headers,
        data: data));

    _interceptors.constructChain(chain);

    if (interceptors != null) {
      if (interceptors is HttpInterceptor) {
        interceptors = new HttpInterceptors.of([interceptors]);
      }
      assert(interceptors is HttpInterceptors);
      interceptors.constructChain(chain);
    }

    chain.forEach((chainFns) {
      future = future.then(chainFns[0], onError: chainFns[1]);
    });

    return future;
  }

  /**
   * Shortcut method for GET requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> get(String url, {
    String data,
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'GET', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Shortcut method for DELETE requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> delete(String url, {
    String data,
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'DELETE', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Shortcut method for HEAD requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> head(String url, {
    String data,
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'HEAD', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Shortcut method for PUT requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> put(String url, String data, {
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'PUT', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Shortcut method for POST requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> post(String url, String data, {
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'POST', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Shortcut method for JSONP requests.  See [call] for a complete description
   * of parameters.
   */
  async.Future<HttpResponse> jsonp(String url, {
    String data,
    Map<String, dynamic> params,
    Map<String, String> headers,
    xsrfHeaderName,
    xsrfCookieName,
    interceptors,
    cache,
    timeout
  }) => call(method: 'JSONP', url: url, data: data, params: params, headers: headers,
             xsrfHeaderName: xsrfHeaderName, xsrfCookieName: xsrfCookieName,
             interceptors: interceptors,
             cache: cache, timeout: timeout);

  /**
   * Parse raw headers into key-value object
   */
  static Map<String, String> parseHeaders(dom.HttpRequest value) {
    var headers = value.getAllResponseHeaders();

    var parsed = {}, key, val, i;

    if (headers == null) return parsed;

    headers.split('\n').forEach((line) {
      i = line.indexOf(':');
      if (i == -1) return;
      key = line.substring(0, i).trim().toLowerCase();
      val = line.substring(i + 1).trim();

      if (key != '') {
        if (parsed.containsKey(key)) {
          parsed[key] += ', ' + val;
        } else {
          parsed[key] = val;
        }
      }
    });
    return parsed;
  }

  /**
   * Returns an [Iterable] of [Future] [HttpResponse]s for the requests
   * that the [Http] service is currently waiting for.
   */
  Iterable<async.Future<HttpResponse> > get pendingRequests {
    return _pendingRequests.values;
  }

  /**
   * DEPRECATED
   */
  async.Future<HttpResponse> request(String rawUrl,
      { HttpResponseConfig config,
        String method: 'GET',
        bool withCredentials: false,
        String responseType,
        String mimeType,
        Map<String, String> requestHeaders,
        sendData,
        void onProgress(dom.ProgressEvent e),
        /*Cache<String, HttpResponse> or false*/ cache }) {
    String url;

    if (config == null) {
      url = _rewriter(rawUrl);
      config = new HttpResponseConfig(url: url);
    } else {
      url = _buildUrl(config.url, config.params);
    }

    if (cache is bool && cache == false) {
      cache = null;
    } else if (cache == null) {
      cache = defaults.cache;
    }
    // We return a pending request only if caching is enabled.
    if (cache != null && _pendingRequests.containsKey(url)) {
      return _pendingRequests[url];
    }
    var cachedValue = (cache != null && method == 'GET') ? cache.get(url) : null;
    if (cachedValue != null) {
      return new async.Future.value(new HttpResponse.copy(cachedValue));
    }

    var result = _backend.request(url,
        method: method,
        withCredentials: withCredentials,
        responseType: responseType,
        mimeType: mimeType,
        requestHeaders: requestHeaders,
        sendData: sendData,
        onProgress: onProgress).then((dom.HttpRequest value) {
      // TODO: Uncomment after apps migrate off of this class.
      // assert(value.status >= 200 && value.status < 300);

      var response = new HttpResponse(
          value.status, value.responseText, parseHeaders(value),
          config);

      if (cache != null) {
        cache.put(url, response);
      }
      _pendingRequests.remove(url);
      return response;
    }, onError: (error) {
      if (error is! dom.ProgressEvent) {
        throw error;
      }
      dom.ProgressEvent event = error;
      _pendingRequests.remove(url);
      dom.HttpRequest request = event.currentTarget;
      return new async.Future.error(
          new HttpResponse(request.status, request.response,
              parseHeaders(request), config));
    });
    _pendingRequests[url] = result;
    return result;
  }

  _buildUrl(String url, Map<String, dynamic> params) {
    if (params == null) return url;
    var parts = [];

    new List.from(params.keys)..sort()..forEach((String key) {
      var value = params[key];
      if (value == null) return;
      if (value is! List) value = [value];

      value.forEach((v) {
        if (v is Map) {
          v = json.stringify(v);
        }
        parts.add(_encodeUriQuery(key) + '=' +
        _encodeUriQuery("$v"));
      });
    });
    return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
  }

  _encodeUriQuery(val, {bool pctEncodeSpaces: false}) =>
    Uri.encodeComponent(val)
      .replaceAll('%40', '@')
      .replaceAll('%3A', ':')
      .replaceAll('%24', r'$')
      .replaceAll('%2C', ',')
      .replaceAll('%20', pctEncodeSpaces ? '%20' : '+');
}
part of angular.core.parser;

typedef ParsedGetter(self, [locals]);
typedef ParsedSetter(self, value, [locals]);

typedef Getter([locals]);
typedef Setter(value, [locals]);

abstract class ParserAST {
  bool get assignable;
}

class Token {
  final int index;
  final String text;

  var value;
  // Tokens should have one of these set.
  String opKey;
  String key;

  Token(this.index, this.text);

  withOp(op) {
    this.opKey = op;
  }

  withGetterSetter(key) {
    this.key = key;
  }

  withValue(value) { this.value = value; }

  toString() => "Token($text)";
}

typedef Operator(dynamic self, Map<String, dynamic>locals, ParserAST a, ParserAST b);

Operator NULL_OP = (_, _x, _0, _1) => null;
Operator NOT_IMPL_OP = (_, _x, _0, _1) { throw "Op not implemented"; };

// FUNCTIONS USED AT RUNTIME.

parserEvalError(String s, String text, stack) =>
  ['Eval Error: $s while evaling [$text]' +
      (stack != null ? '\n\nFROM:\n$stack' : '')];

// Automatic type conversion.
autoConvertAdd(a, b) {
  if (a != null && b != null) {
    // TODO(deboer): Support others.
    if (a is String && b is! String) {
      return a + b.toString();
    }
    if (a is! String && b is String) {
      return a.toString() + b;
    }
    return a + b;
  }
  if (a != null) return a;
  if (b != null) return b;
  return null;
}

objectIndexGetField(o, i, evalError) {
  if (o == null) throw evalError('Accessing null object');

  if (o is List) {
    return o[i.toInt()];
  } else if (o is Map) {
    return o[i.toString()]; // toString dangerous?
  }
  throw evalError("Attempted field access on a non-list, non-map");
}

objectIndexSetField(o, i, v, evalError) {
  if (o is List) {
    int arrayIndex = i.toInt();
    if (o.length <= arrayIndex) { o.length = arrayIndex + 1; }
    o[arrayIndex] = v;
  } else if (o is Map) {
    o[i.toString()] = v; // toString dangerous?
  } else {
    throw evalError("Attempting to set a field on a non-list, non-map");
  }
  return v;
}

safeFunctionCall(userFn, fnName, evalError) {
  if (userFn == null) {
    throw evalError("Undefined function $fnName");
  }
  if (userFn is! Function) {
    throw evalError("$fnName is not a function");
  }
  return userFn;
}


Map<String, Operator> OPERATORS = {
  'undefined': NULL_OP,
  'null': NULL_OP,
  'true': (self, locals, a, b) => true,
  'false': (self, locals, a, b) => false,
  '+': (self, locals, aFn, bFn) {
    var a = aFn.eval(self, locals);
    var b = bFn.eval(self, locals);
    return autoConvertAdd(a, b);
  },
  '-': (self, locals, a, b) {
    assert(a != null || b != null);
    var aResult = a != null ? a.eval(self, locals) : null;
    var bResult = b != null ? b.eval(self, locals) : null;
    return (aResult == null ? 0 : aResult) - (bResult == null ? 0 : bResult);
  },
  '*': (s, l, a, b) => a.eval(s, l) * b.eval(s, l),
  '/': (s, l, a, b) => a.eval(s, l) / b.eval(s, l),
  '%': (s, l, a, b) => a.eval(s, l) % b.eval(s, l),
  '^': (s, l, a, b) => a.eval(s, l) ^ b.eval(s, l),
  '=': NULL_OP,
  '==': (s, l, a, b) => a.eval(s, l) == b.eval(s, l),
  '!=': (s, l, a, b) => a.eval(s, l) != b.eval(s, l),
  '<': (s, l, a, b) => a.eval(s, l) < b.eval(s, l),
  '>': (s, l, a, b) => a.eval(s, l) > b.eval(s, l),
  '<=': (s, l, a, b) => a.eval(s, l) <= b.eval(s, l),
  '>=': (s, l, a, b) => a.eval(s, l) >= b.eval(s, l),
  '&&': (s, l, a, b) => toBool(a.eval(s, l)) && toBool(b.eval(s, l)),
  '||': (s, l, a, b) => toBool(a.eval(s, l)) || toBool(b.eval(s, l)),
  '&': (s, l, a, b) => a.eval(s, l) & b.eval(s, l),
  '|': NOT_IMPL_OP, //b(locals)(locals, a(locals))
  '!': (self, locals, a, b) => !toBool(a.eval(self, locals))
};

class DynamicParser implements Parser {
  final Profiler _perf;
  final Lexer _lexer;
  final ParserBackend _b;

  DynamicParser(Profiler this._perf, Lexer this._lexer, ParserBackend this._b);

  List<Token> _tokens;
  String _text;
  var _evalError;

  ParserAST call(String text) {
    try {
      if (text == null) text = '';
      _tokenSavers = [];
      _text = text;
      _tokens = _lexer.call(text);
      _evalError = (String s, [stack]) => parserEvalError(s, text, stack);

      ParserAST value = _statements();

      if (_tokens.length != 0) {
        throw _parserError("Unconsumed token ${_tokens[0].text}");
      }
      return _perf == null ? value : _b.profiled(value, _perf, text);
    } finally {
      _tokens = null;
      _text = null;
      _evalError = null;
      _tokenSavers = null;
    }
  }

  primaryFromToken(Token token, parserError) {
    if (token.key != null) {
      return _b.getterSetter(token.key);
    }
    if (token.opKey != null) {
      return _b.fromOperator(token.opKey);
    }
    if (token.value != null) {
      return _b.value(token.value);
    }
    if (token.text != null) {
      return _b.value(token.text);
    }
    throw parserError("Internal Angular Error: Tokens should have keys, text or fns");
  }

  _parserError(String s, [Token t]) {
    if (t == null && !_tokens.isEmpty) t = _tokens[0];
    String location = t == null ?
      'the end of the expression' :
      'at column ${t.index + 1} in';
    return 'Parser Error: $s $location [$_text]';
  }


  Token _peekToken() {
    if (_tokens.length == 0)
      throw "Unexpected end of expression: " + _text;
    return _tokens[0];
  }

  Token _peek([String e1, String e2, String e3, String e4]) {
    if (_tokens.length > 0) {
      Token token = _tokens[0];
      String t = token.text;
      if (t==e1 || t==e2 || t==e3 || t==e4 ||
      (e1 == null && e2 == null && e3 == null && e4 == null)) {
        return token;
      }
    }
    return null;
  }

  /**
   * Token savers are synchronous lists that allows Parser functions to
   * access the tokens parsed during some amount of time.  They are useful
   * for printing helpful debugging messages.
   */
  List<List<Token>> _tokenSavers;
  List<Token> _saveTokens() { var n = []; _tokenSavers.add(n); return n; }
  _stopSavingTokens(x) { if (!_tokenSavers.remove(x)) { throw 'bad token saver'; } return x; }
  _tokensText(List x) => x.map((x) => x.text).join();


  Token _expect([String e1, String e2, String e3, String e4]){
    Token token = _peek(e1, e2, e3, e4);
    if (token != null) {
      var consumed = _tokens.removeAt(0);
      _tokenSavers.forEach((ts) => ts.add(consumed));
      return token;
    }
    return null;
  }

  ParserAST _consume(e1){
    if (_expect(e1) == null) {
      throw _parserError("Missing expected $e1");
    }
  }

  ParserAST _primary() {
    var primary;
    var ts = _saveTokens();
    if (_expect('(') != null) {
      primary = _filterChain();
      _consume(')');
    } else if (_expect('[') != null) {
      primary = _arrayDeclaration();
    } else if (_expect('{') != null) {
      primary = _object();
    } else {
      Token token = _expect();
      primary = primaryFromToken(token, _parserError);
      if (primary == null) {
        throw _parserError("Internal Angular Error: Unreachable code A.");
      }
    }

    var next;
    while ((next = _expect('(', '[', '.')) != null) {
      if (next.text == '(') {
        primary = _functionCall(primary, _tokensText(ts.sublist(0, ts.length - 1)));
      } else if (next.text == '[') {
        primary = _objectIndex(primary);
      } else if (next.text == '.') {
        primary = _fieldAccess(primary);
      } else {
        throw _parserError("Internal Angular Error: Unreachable code B.");
      }
    }
    _stopSavingTokens(ts);
    return primary;
  }

  ParserAST _binaryFn(ParserAST left, String op, ParserAST right) =>
      _b.binaryFn(left, op, right);

  ParserAST _unaryFn(String op, ParserAST right) =>
      _b.unaryFn(op, right);

  ParserAST _unary() {
    var token;
    if (_expect('+') != null) {
      return _primary();
    } else if ((token = _expect('-')) != null) {
      return _binaryFn(_b.zero(), token.opKey, _unary());
    } else if ((token = _expect('!')) != null) {
      return _unaryFn(token.opKey, _unary());
    } else {
      return _primary();
    }
  }

  ParserAST _multiplicative() {
    var left = _unary();
    var token;
    while ((token = _expect('*','/','%')) != null) {
      left = _binaryFn(left, token.opKey, _unary());
    }
    return left;
  }

  ParserAST _additive() {
    var left = _multiplicative();
    var token;
    while ((token = _expect('+','-')) != null) {
      left = _binaryFn(left, token.opKey, _multiplicative());
    }
    return left;
  }

  ParserAST _relational() {
    var left = _additive();
    var token;
    if ((token = _expect('<', '>', '<=', '>=')) != null) {
      left = _binaryFn(left, token.opKey, _relational());
    }
    return left;
  }

  ParserAST _equality() {
    var left = _relational();
    var token;
    if ((token = _expect('==','!=')) != null) {
      left = _binaryFn(left, token.opKey, _equality());
    }
    return left;
  }

  ParserAST _logicalAND() {
    var left = _equality();
    var token;
    if ((token = _expect('&&')) != null) {
      left = _binaryFn(left, token.opKey, _logicalAND());
    }
    return left;
  }

  ParserAST _logicalOR() {
    var left = _logicalAND();
    var token;
    while(true) {
      if ((token = _expect('||')) != null) {
        left = _binaryFn(left, token.opKey, _logicalAND());
      } else {
        return left;
      }
    }
  }

  ParserAST _assignment() {
    var ts = _saveTokens();
    var left = _logicalOR();
    _stopSavingTokens(ts);
    var right;
    var token;
    if ((token = _expect('=')) != null) {
      if (!left.assignable) {
        throw _parserError('Expression ${_tokensText(ts)} is not assignable', token);
      }
      right = _logicalOR();
      return _b.assignment(left, right, _evalError);
    } else {
      return left;
    }
  }


  ParserAST _expression() {
    return _assignment();
  }

  _filterChain() {
    var left = _expression();
    var token;
    while(true) {
      if ((token = _expect('|')) != null) {
        left = _filter(left);
      } else {
        return left;
      }
    }
  }

  ParserAST _filter(ParserAST left) {
    var token = _expect();
    var filterName = token.text;
    var argsFn = [];
    while(true) {
      if ((token = _expect(':')) != null) {
        argsFn.add(_expression());
      } else {
        return _b.filter(filterName, left, argsFn, _evalError);
      }
    }
  }


  _statements() {
    List<ParserAST> statements = [];
    while (true) {
      if (_tokens.length > 0 && _peek('}', ')', ';', ']') == null)
        statements.add(_filterChain());
      if (_expect(';') == null) {
        return statements.length == 1
        ? statements[0]
        : _b.multipleStatements(statements);
      }
    }
  }

  _functionCall(fn, fnName) {
    var argsFn = [];
    if (_peekToken().text != ')') {
      do {
        argsFn.add(_expression());
      } while (_expect(',') != null);
    }
    _consume(')');
    return _b.functionCall(fn, fnName, argsFn, _evalError);
  }

  // This is used with json array declaration
  _arrayDeclaration() {
    var elementFns = [];
    if (_peekToken().text != ']') {
      do {
        elementFns.add(_expression());
      } while (_expect(',') != null);
    }
    _consume(']');
    return _b.arrayDeclaration(elementFns);
  }

  _objectIndex(obj) {
    var indexFn = _expression();
    _consume(']');
    return _b.objectIndex(obj, indexFn, _evalError);
  }

  _fieldAccess(object) {
    var field = _expect().text;
    //var getter = getter(field);
    return _b.fieldAccess(object, field);
  }

  _object() {
    var keyValues = [];
    if (_peekToken().text != '}') {
      do {
        var token = _expect(),
        key = token.value != null && token.value is String ? token.value : token.text;
        _consume(":");
        var value = _expression();
        keyValues.add({"key":key, "value":value});
      } while (_expect(',') != null);
    }
    _consume('}');
    return _b.object(keyValues);
  }

}
part of angular.directive;

/**
 * Base class for NgIfAttrDirective and NgUnlessAttrDirective.
 */
abstract class _NgUnlessIfAttrDirectiveBase {
  final BoundBlockFactory _boundBlockFactory;
  final BlockHole _blockHole;
  final Scope _scope;

  Block _block;

  /**
   * The new child scope.  This child scope is recreated whenever the `ng-if`
   * subtree is inserted into the DOM and destroyed when it's removed from the
   * DOM.  Refer
   * https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance
   */
  Scope _childScope;

  _NgUnlessIfAttrDirectiveBase(BoundBlockFactory this._boundBlockFactory,
                               BlockHole this._blockHole,
                               Scope this._scope);

  // Override in subclass.
  set condition(value);

  void _ensureBlockExists() {
    if (_block == null) {
      _childScope = _scope.$new();
      _block = _boundBlockFactory(_childScope);
      _block.insertAfter(_blockHole);
    }
  }

  void _ensureBlockDestroyed() {
    if (_block != null) {
      _block.remove();
      _childScope.$destroy();
      _block = null;
      _childScope = null;
    }
  }
}


/**
 * The `ng-if` directive compliments the `ng-unless` (provided by
 * [NgUnlessAttrDirective]) directive.
 *
 * directive based on the **truthy/falsy** value of the provided expression.
 * Specifically, if the expression assigned to `ng-if` evaluates to a `false`
 * value, then the subtree is removed from the DOM.  Otherwise, *a clone of the
 * subtree* is reinserted into the DOM.  This clone is created from the compiled
 * state.  As such, modifications made to the element after compilation (e.g.
 * changing the `class`) are lost when the element is destroyed.
 *
 * Whenever the subtree is inserted into the DOM, it always gets a new child
 * scope.  This child scope is destroyed when the subtree is removed from the
 * DOM.  Refer
 * https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance
 *
 * This has an important implication when `ng-model` is used inside an `ng-if`
 * to bind to a javascript primitive defined in the parent scope.  In such a
 * situation, any modifications made to the variable in the `ng-if` subtree will
 * be made on the child scope and override (hide) the value in the parent scope.
 * The parent scope will remain unchanged by changes affected by this subtree.
 *
 * Note: `ng-if` differs from `ng-show` and `ng-hide` in that `ng-if` completely
 * removes and recreates the element in the DOM rather than changing its
 * visibility via the `display` css property.  A common case when this
 * difference is significant is when using css selectors that rely on an
 * element's position within the DOM (HTML), such as the `:first-child` or
 * `:last-child` pseudo-classes.
 *
 * Example:
 *
 *     <!-- By using ng-if instead of ng-show, we avoid the cost of the showdown
 *          filter, the repeater, etc. -->
 *     <div ng-if="showDetails">
 *        {{obj.details.markdownText | showdown}}
 *        <div ng-repeat="item in obj.details.items">
 *          ...
 *        </div>
 *     </div>
 */
@NgDirective(
    children: NgAnnotation.TRANSCLUDE_CHILDREN,
    selector:'[ng-if]',
    map: const {'.': '=.condition'})
class NgIfDirective extends _NgUnlessIfAttrDirectiveBase {
  NgIfDirective(BoundBlockFactory boundBlockFactory,
                    BlockHole blockHole,
                    Scope scope): super(boundBlockFactory, blockHole, scope);

  set condition(value) =>
      (toBool(value) ? _ensureBlockExists() : _ensureBlockDestroyed());
}


/**
 * The `ng-unless` directive compliments the `ng-if` (provided by
 * [NgIfAttrDirective]) directive.
 *
 * The `ng-unless` directive recreates/destroys the DOM subtree containing the
 * directive based on the **falsy/truthy** value of the provided expression.
 * Specifically, if the expression assigned to `ng-unless` evaluates to a `true`
 * value, then the subtree is removed from the DOM.  Otherwise, *a clone of the
 * subtree* is reinserted into the DOM.  This clone is created from the compiled
 * state.  As such, modifications made to the element after compilation (e.g.
 * changing the `class`) are lost when the element is destroyed.
 *
 * Whenever the subtree is inserted into the DOM, it always gets a new child
 * scope.  This child scope is destroyed when the subtree is removed from the
 * DOM.  Refer
 * https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance
 *
 * This has an important implication when `ng-model` is used inside an
 * `ng-unless` to bind to a javascript primitive defined in the parent scope.
 * In such a situation, any modifications made to the variable in the
 * `ng-unless` subtree will be made on the child scope and override (hide) the
 * value in the parent scope.  The parent scope will remain unchanged by changes
 * affected by this subtree.
 *
 * Note: `ng-unless` differs from `ng-show` and `ng-hide` in that `ng-unless`
 * completely removes and recreates the element in the DOM rather than changing
 * its visibility via the `display` css property.  A common case when this
 * difference is significant is when using css selectors that rely on an
 * element's position within the DOM (HTML), such as the `:first-child` or
 * `:last-child` pseudo-classes.
 *
 * Example:
 *
 *     <!-- By using ng-unless instead of ng-show, we avoid the cost of the showdown
 *          filter, the repeater, etc. -->
 *     <div ng-unless="terseView">
 *        {{obj.details.markdownText | showdown}}
 *        <div ng-repeat="item in obj.details.items">
 *          ...
 *        </div>
 *     </div>
 */
@NgDirective(
    children: NgAnnotation.TRANSCLUDE_CHILDREN,
    selector:'[ng-unless]',
    map: const {'.': '=.condition'})
class NgUnlessDirective extends _NgUnlessIfAttrDirectiveBase {

  NgUnlessDirective(BoundBlockFactory boundBlockFactory,
                        BlockHole blockHole,
                        Scope scope): super(boundBlockFactory, blockHole, scope);

  set condition(value) =>
      (!toBool(value) ? _ensureBlockExists() : _ensureBlockDestroyed());
}
// 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.

part of intl;
/**
 * Provides the ability to format a number in a locale-specific way. The
 * format is specified as a pattern using a subset of the ICU formatting
 * patterns.
 *
 * - `0` A single digit
 * - `#` A single digit, omitted if the value is zero
 * - `.` Decimal separator
 * - `-` Minus sign
 * - `,` Grouping separator
 * - `E` Separates mantissa and expontent
 * - `+` - Before an exponent, indicates it should be prefixed with a plus sign.
 * - `%` - In prefix or suffix, multiply by 100 and show as percentage
 * - `‰ (\u2030)` In prefix or suffix, multiply by 1000 and show as per mille
 * - `¤ (\u00A4)` Currency sign, replaced by currency name
 * - `'` Used to quote special characters
 * - `;` Used to separate the positive and negative patterns if both are present
 *
 * For example,
 *       var f = new NumberFormat("###.0#", "en_US");
 *       print(f.format(12.345));
 *       ==> 12.34
 * If the locale is not specified, it will default to the current locale. If
 * the format is not specified it will print in a basic format with at least
 * one integer digit and three fraction digits.
 *
 * There are also standard patterns available via the special constructors. e.g.
 *       var symbols = new NumberFormat.percentFormat("ar");
 * There are four such constructors: decimalFormat, percentFormat,
 * scientificFormat and currencyFormat. However, at the moment,
 * scientificFormat prints only as equivalent to "#E0" and does not take
 * into account significant digits. currencyFormat will always use the name
 * of the currency rather than the symbol.
 */
class NumberFormat {
  /** Variables to determine how number printing behaves. */
  // TODO(alanknight): If these remain as variables and are set based on the
  // pattern, can we make them final?
  String _negativePrefix = '-';
  String _positivePrefix = '';
  String _negativeSuffix = '';
  String _positiveSuffix = '';
  /**
   * How many numbers in a group when using punctuation to group digits in
   * large numbers. e.g. in en_US: "1,000,000" has a grouping size of 3 digits
   * between commas.
   */
  int _groupingSize = 3;
  bool _decimalSeparatorAlwaysShown = false;
  bool _useSignForPositiveExponent = false;
  bool _useExponentialNotation = false;

  int maximumIntegerDigits = 40;
  int minimumIntegerDigits = 1;
  int maximumFractionDigits = 3;
  int minimumFractionDigits = 0;
  int minimumExponentDigits = 0;

  int _multiplier = 1;

  /**
   * Stores the pattern used to create this format. This isn't used, but
   * is helpful in debugging.
   */
  String _pattern;

  /** The locale in which we print numbers. */
  final String _locale;

  /** Caches the symbols used for our locale. */
  NumberSymbols _symbols;

  /**
   * Transient internal state in which to build up the result of the format
   * operation. We can have this be just an instance variable because Dart is
   * single-threaded and unless we do an asynchronous operation in the process
   * of formatting then there will only ever be one number being formatted
   * at a time. In languages with threads we'd need to pass this on the stack.
   */
  StringBuffer _buffer;

  /**
   * Create a number format that prints using [newPattern] as it applies in
   * [locale].
   */
  factory NumberFormat([String newPattern, String locale]) {
    return new NumberFormat._forPattern(locale, (x) => newPattern);
  }

  /** Create a number format that prints as DECIMAL_PATTERN. */
  NumberFormat.decimalPattern([String locale]) :
      this._forPattern(locale, (x) => x.DECIMAL_PATTERN);

  /** Create a number format that prints as PERCENT_PATTERN. */
  NumberFormat.percentPattern([String locale]) :
    this._forPattern(locale, (x) => x.PERCENT_PATTERN);

  /** Create a number format that prints as SCIENTIFIC_PATTERN. */
  NumberFormat.scientificPattern([String locale]) :
    this._forPattern(locale, (x) => x.SCIENTIFIC_PATTERN);

  /** Create a number format that prints as CURRENCY_PATTERN. */
  NumberFormat.currencyPattern([String locale]) :
    this._forPattern(locale, (x) => x.CURRENCY_PATTERN);

  /**
   * Create a number format that prints in a pattern we get from
   * the [getPattern] function using the locale [locale].
   */
  NumberFormat._forPattern(String locale, Function getPattern) :
      _locale = Intl.verifiedLocale(locale, localeExists) {
    _symbols = numberFormatSymbols[_locale];
    _setPattern(getPattern(_symbols));
  }

  /**
   * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
   */
  String get locale => _locale;

  /**
   * Return true if the locale exists, or if it is null. The null case
   * is interpreted to mean that we use the default locale.
   */
  static bool localeExists(localeName) {
    if (localeName == null) return false;
    return numberFormatSymbols.containsKey(localeName);
  }

  /**
   * Return the symbols which are used in our locale. Cache them to avoid
   * repeated lookup.
   */
  NumberSymbols get symbols {
    return _symbols;
  }

  /**
   * Format [number] according to our pattern and return the formatted string.
   */
  String format(num number) {
    // TODO(alanknight): Do we have to do anything for printing numbers bidi?
    // Or are they always printed left to right?
    if (number.isNaN) return symbols.NAN;
    if (number.isInfinite) return "${_signPrefix(number)}${symbols.INFINITY}";

    _newBuffer();
    _add(_signPrefix(number));
    _formatNumber(number.abs() * _multiplier);
    _add(_signSuffix(number));

    var result = _buffer.toString();
    _buffer = null;
    return result;
  }

  /**
   * Format the main part of the number in the form dictated by the pattern.
   */
  void _formatNumber(num number) {
    if (_useExponentialNotation) {
      _formatExponential(number);
    } else {
      _formatFixed(number);
    }
  }

  /** Format the number in exponential notation. */
  void _formatExponential(num number) {
    if (number == 0.0) {
      _formatFixed(number);
      _formatExponent(0);
      return;
    }

    var exponent = (log(number) / log(10)).floor();
    var mantissa = number / pow(10.0, exponent);

    var minIntDigits = minimumIntegerDigits;
    if (maximumIntegerDigits > 1 &&
        maximumIntegerDigits > minimumIntegerDigits) {
      // A repeating range is defined; adjust to it as follows.
      // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
      // -3,-4,-5=>-6, etc. This takes into account that the
      // exponent we have here is off by one from what we expect;
      // it is for the format 0.MMMMMx10^n.
      while ((exponent % maximumIntegerDigits) != 0) {
        mantissa *= 10;
        exponent--;
      }
      minIntDigits = 1;
    } else {
      // No repeating range is defined, use minimum integer digits.
      if (minimumIntegerDigits < 1) {
        exponent++;
        mantissa /= 10;
      } else {
        exponent -= minimumIntegerDigits - 1;
        mantissa *= pow(10, minimumIntegerDigits - 1);
      }
    }
    _formatFixed(mantissa);
    _formatExponent(exponent);
  }

  /**
   * Format the exponent portion, e.g. in "1.3e-5" the "e-5".
   */
  void _formatExponent(num exponent) {
    _add(symbols.EXP_SYMBOL);
    if (exponent < 0) {
      exponent = -exponent;
      _add(symbols.MINUS_SIGN);
    } else if (_useSignForPositiveExponent) {
      _add(symbols.PLUS_SIGN);
    }
    _pad(minimumExponentDigits, exponent.toString());
  }

  /** Used to test if we have exceeded Javascript integer limits. */
  final _maxInt = pow(2, 52);

  /**
   * Format the basic number portion, inluding the fractional digits.
   */
  void _formatFixed(num number) {
    // Very fussy math to get integer and fractional parts.
    var power = pow(10, maximumFractionDigits);
    var shiftedNumber = (number * power);
    // We must not roundToDouble() an int or it will lose precision. We must not
    // round() a large double or it will take its loss of precision and
    // preserve it in an int, which we will then print to the right
    // of the decimal place. Therefore, only roundToDouble if we are already
    // a double.
    if (shiftedNumber is double) {
      shiftedNumber = shiftedNumber.roundToDouble();
    }
    var intValue, fracValue;
    if (shiftedNumber.isInfinite) {
      intValue = number.toInt();
      fracValue = 0;
    } else {
      intValue = shiftedNumber.round() ~/ power;
      fracValue = (shiftedNumber - intValue * power).floor();
    }
    var fractionPresent = minimumFractionDigits > 0 || fracValue > 0;

    // If the int part is larger than 2^52 and we're on Javascript (so it's
    // really a float) it will lose precision, so pad out the rest of it
    // with zeros. Check for Javascript by seeing if an integer is double.
    var paddingDigits = new StringBuffer();
    if (1 is double && intValue > _maxInt) {
        var howManyDigitsTooBig = (log(intValue) / LN10).ceil() - 16;
        var divisor = pow(10, howManyDigitsTooBig).round();
        for (var each in new List(howManyDigitsTooBig.toInt())) {
          paddingDigits.write(symbols.ZERO_DIGIT);
        }
        intValue = (intValue / divisor).truncate();
    }
    var integerDigits = "${intValue}${paddingDigits}".codeUnits;
    var digitLength = integerDigits.length;

    if (_hasPrintableIntegerPart(intValue)) {
      _pad(minimumIntegerDigits - digitLength);
      for (var i = 0; i < digitLength; i++) {
        _addDigit(integerDigits[i]);
        _group(digitLength, i);
      }
    } else if (!fractionPresent) {
      // If neither fraction nor integer part exists, just print zero.
      _addZero();
    }

    _decimalSeparator(fractionPresent);
    _formatFractionPart((fracValue + power).toString());
  }

  /**
   * Format the part after the decimal place in a fixed point number.
   */
  void _formatFractionPart(String fractionPart) {
    var fractionCodes = fractionPart.codeUnits;
    var fractionLength = fractionPart.length;
    while(fractionCodes[fractionLength - 1] == _zero &&
           fractionLength > minimumFractionDigits + 1) {
      fractionLength--;
    }
    for (var i = 1; i < fractionLength; i++) {
      _addDigit(fractionCodes[i]);
    }
  }

  /** Print the decimal separator if appropriate. */
  void _decimalSeparator(bool fractionPresent) {
    if (_decimalSeparatorAlwaysShown || fractionPresent) {
      _add(symbols.DECIMAL_SEP);
    }
  }

  /**
   * Return true if we have a main integer part which is printable, either
   * because we have digits left of the decimal point, or because there are
   * a minimum number of printable digits greater than 1.
   */
  bool _hasPrintableIntegerPart(int intValue) {
    return intValue > 0 || minimumIntegerDigits > 0;
  }

  /**
   * Create a new empty buffer. See comment on [_buffer] variable for why
   * we have it as an instance variable rather than passing it on the stack.
   */
  void _newBuffer() { _buffer = new StringBuffer(); }

  /** A group of methods that provide support for writing digits and other
   * required characters into [_buffer] easily.
   */
  void _add(String x) { _buffer.write(x);}
  void _addCharCode(int x) { _buffer.writeCharCode(x); }
  void _addZero() { _buffer.write(symbols.ZERO_DIGIT); }
  void _addDigit(int x) { _buffer.writeCharCode(_localeZero + x - _zero); }

  /** Print padding up to [numberOfDigits] above what's included in [basic]. */
  void _pad(int numberOfDigits, [String basic = '']) {
    for (var i = 0; i < numberOfDigits - basic.length; i++) {
      _add(symbols.ZERO_DIGIT);
    }
    for (var x in basic.codeUnits) {
      _addDigit(x);
    }
  }

  /**
   * We are printing the digits of the number from left to right. We may need
   * to print a thousands separator or other grouping character as appropriate
   * to the locale. So we find how many places we are from the end of the number
   * by subtracting our current [position] from the [totalLength] and print
   * the separator character every [_groupingSize] digits.
   */
  void _group(int totalLength, int position) {
    var distanceFromEnd = totalLength - position;
    if (distanceFromEnd <= 1 || _groupingSize <= 0) return;
    if (distanceFromEnd % _groupingSize == 1) {
      _add(symbols.GROUP_SEP);
    }
  }

  /** Returns the code point for the character '0'. */
  final _zero = '0'.codeUnits.first;

  /** Returns the code point for the locale's zero digit. */
  // Note that there is a slight risk of a locale's zero digit not fitting
  // into a single code unit, but it seems very unlikely, and if it did,
  // there's a pretty good chance that our assumptions about being able to do
  // arithmetic on it would also be invalid.
  get _localeZero => symbols.ZERO_DIGIT.codeUnits.first;

  /**
   * Returns the prefix for [x] based on whether it's positive or negative.
   * In en_US this would be '' and '-' respectively.
   */
  String _signPrefix(num x) {
    return x.isNegative ? _negativePrefix : _positivePrefix;
  }

  /**
   * Returns the suffix for [x] based on wether it's positive or negative.
   * In en_US there are no suffixes for positive or negative.
   */
  String _signSuffix(num x) {
    return x.isNegative ? _negativeSuffix : _positiveSuffix;
  }

  void _setPattern(String newPattern) {
    if (newPattern == null) return;
    // Make spaces non-breaking
    _pattern = newPattern.replaceAll(' ', '\u00a0');
    var parser = new _NumberFormatParser(this, newPattern);
    parser.parse();
  }

  String toString() => "NumberFormat($_locale, $_pattern)";
}

/**
 * Private class that parses the numeric formatting pattern and sets the
 * variables in [format] to appropriate values. Instances of this are
 * transient and store parsing state in instance variables, so can only be used
 * to parse a single pattern.
 */
class _NumberFormatParser {

  /**
   * The special characters in the pattern language. All others are treated
   * as literals.
   */
  static const _PATTERN_SEPARATOR = ';';
  static const _QUOTE = "'";
  static const _PATTERN_DIGIT = '#';
  static const _PATTERN_ZERO_DIGIT = '0';
  static const _PATTERN_GROUPING_SEPARATOR = ',';
  static const _PATTERN_DECIMAL_SEPARATOR = '.';
  static const _PATTERN_CURRENCY_SIGN = '\u00A4';
  static const _PATTERN_PER_MILLE = '\u2030';
  static const _PATTERN_PERCENT = '%';
  static const _PATTERN_EXPONENT = 'E';
  static const _PATTERN_PLUS = '+';

  /** The format whose state we are setting. */
  final NumberFormat format;

  /** The pattern we are parsing. */
  final _StringIterator pattern;

  /**
   * Create a new [_NumberFormatParser] for a particular [NumberFormat] and
   * [input] pattern.
   */
  _NumberFormatParser(this.format, input) : pattern = _iterator(input) {
    pattern.moveNext();
  }

  /** The [NumberSymbols] for the locale in which our [format] prints. */
  NumberSymbols get symbols => format.symbols;

  /** Parse the input pattern and set the values. */
  void parse() {
    format._positivePrefix = _parseAffix();
    var trunk = _parseTrunk();
    format._positiveSuffix = _parseAffix();
    // If we have separate positive and negative patterns, now parse the
    // the negative version.
    if (pattern.current == _NumberFormatParser._PATTERN_SEPARATOR) {
      pattern.moveNext();
      format._negativePrefix = _parseAffix();
      // Skip over the negative trunk, verifying that it's identical to the
      // positive trunk.
      for (var each in _iterable(trunk)) {
        if (pattern.current != each && pattern.current != null) {
          throw new FormatException(
              "Positive and negative trunks must be the same");
        }
        pattern.moveNext();
      }
      format._negativeSuffix = _parseAffix();
    } else {
      // If no negative affix is specified, they share the same positive affix.
      format._negativePrefix = format._positivePrefix + format._negativePrefix;
      format._negativeSuffix = format._negativeSuffix + format._positiveSuffix;
    }
  }

  /** Variable used in parsing prefixes and suffixes to keep track of
   * whether or not we are in a quoted region. */
  bool inQuote = false;

  /**
   * Parse a prefix or suffix and return the prefix/suffix string. Note that
   * this also may modify the state of [format].
   */
  String _parseAffix() {
    var affix = new StringBuffer();
    inQuote = false;
    var loop = true;
    while (loop) {
      loop = parseCharacterAffix(affix) && pattern.moveNext();
    }
    return affix.toString();
  }

  /**
   * Parse an individual character as part of a prefix or suffix.  Return true
   * if we should continue to look for more affix characters, and false if
   * we have reached the end.
   */
  bool parseCharacterAffix(StringBuffer affix) {
    var ch = pattern.current;
    if (ch == null) return false;
    if (ch == _QUOTE) {
      var nextChar = pattern.peek;
      if (nextChar == _QUOTE) {
        pattern.moveNext();
        affix.write(_QUOTE); // 'don''t'
      } else {
        inQuote = !inQuote;
      }
      return true;
    }

    if (inQuote) {
      affix.write(ch);
    } else {
      switch (ch) {
        case _PATTERN_DIGIT:
        case _PATTERN_ZERO_DIGIT:
        case _PATTERN_GROUPING_SEPARATOR:
        case _PATTERN_DECIMAL_SEPARATOR:
        case _PATTERN_SEPARATOR:
          return false;
        case _PATTERN_CURRENCY_SIGN:
          // TODO(alanknight): Handle the local/global/portable currency signs
          affix.write(symbols.DEF_CURRENCY_CODE);
          break;
        case _PATTERN_PERCENT:
          if (format._multiplier != 1) {
            throw new FormatException('Too many percent/permill');
          }
          format._multiplier = 100;
          affix.write(symbols.PERCENT);
          break;
        case _PATTERN_PER_MILLE:
          if (format._multiplier != 1) {
            throw new FormatException('Too many percent/permill');
          }
          format._multiplier = 1000;
          affix.write(symbols.PERMILL);
          break;
        default:
          affix.write(ch);
      }
    }
    return true;
  }

  /** Variables used in [_parseTrunk] and [parseTrunkCharacter]. */
  var decimalPos;
  var digitLeftCount;
  var zeroDigitCount;
  var digitRightCount;
  var groupingCount;
  var trunk;

  /**
   * Parse the "trunk" portion of the pattern, the piece that doesn't include
   * positive or negative prefixes or suffixes.
   */
  String _parseTrunk() {
    decimalPos = -1;
    digitLeftCount = 0;
    zeroDigitCount = 0;
    digitRightCount = 0;
    groupingCount = -1;

    var loop = true;
    trunk = new StringBuffer();
    while (pattern.current != null && loop) {
      loop = parseTrunkCharacter();
    }

    if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
      // Handle '###.###' and '###.' and '.###'
      var n = decimalPos;
      if (n == 0) { // Handle '.###'
        n++;
      }
      digitRightCount = digitLeftCount - n;
      digitLeftCount = n - 1;
      zeroDigitCount = 1;
    }

    // Do syntax checking on the digits.
    if (decimalPos < 0 && digitRightCount > 0 ||
        decimalPos >= 0 && (decimalPos < digitLeftCount ||
            decimalPos > digitLeftCount + zeroDigitCount) ||
            groupingCount == 0) {
      throw new FormatException('Malformed pattern "${pattern.input}"');
    }
    var totalDigits = digitLeftCount + zeroDigitCount + digitRightCount;

    format.maximumFractionDigits =
        decimalPos >= 0 ? totalDigits - decimalPos : 0;
    if (decimalPos >= 0) {
      format.minimumFractionDigits =
          digitLeftCount + zeroDigitCount - decimalPos;
      if (format.minimumFractionDigits < 0) {
        format.minimumFractionDigits = 0;
      }
    }

    // The effectiveDecimalPos is the position the decimal is at or would be at
    // if there is no decimal. Note that if decimalPos<0, then digitTotalCount
    // == digitLeftCount + zeroDigitCount.
    var effectiveDecimalPos = decimalPos >= 0 ? decimalPos : totalDigits;
    format.minimumIntegerDigits = effectiveDecimalPos - digitLeftCount;
    if (format._useExponentialNotation) {
      format.maximumIntegerDigits =
          digitLeftCount + format.minimumIntegerDigits;

      // In exponential display, we need to at least show something.
      if (format.maximumFractionDigits == 0 &&
          format.minimumIntegerDigits == 0) {
        format.minimumIntegerDigits = 1;
      }
    }

    format._groupingSize = max(0, groupingCount);
    format._decimalSeparatorAlwaysShown = decimalPos == 0 ||
        decimalPos == totalDigits;

    return trunk.toString();
  }

  /**
   * Parse an individual character of the trunk. Return true if we should
   * continue to look for additional trunk characters or false if we have
   * reached the end.
   */
  bool parseTrunkCharacter() {
    var ch = pattern.current;
    switch (ch) {
      case _PATTERN_DIGIT:
        if (zeroDigitCount > 0) {
          digitRightCount++;
        } else {
          digitLeftCount++;
        }
        if (groupingCount >= 0 && decimalPos < 0) {
          groupingCount++;
        }
        break;
      case _PATTERN_ZERO_DIGIT:
        if (digitRightCount > 0) {
          throw new FormatException('Unexpected "0" in pattern "'
              + pattern.input + '"');
        }
        zeroDigitCount++;
        if (groupingCount >= 0 && decimalPos < 0) {
          groupingCount++;
        }
        break;
      case _PATTERN_GROUPING_SEPARATOR:
        groupingCount = 0;
        break;
      case _PATTERN_DECIMAL_SEPARATOR:
        if (decimalPos >= 0) {
          throw new FormatException(
              'Multiple decimal separators in pattern "$pattern"');
        }
        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
        break;
      case _PATTERN_EXPONENT:
        trunk.write(ch);
        if (format._useExponentialNotation) {
          throw new FormatException(
              'Multiple exponential symbols in pattern "$pattern"');
        }
        format._useExponentialNotation = true;
        format.minimumExponentDigits = 0;

        // exponent pattern can have a optional '+'.
        pattern.moveNext();
        var nextChar = pattern.current;
        if (nextChar == _PATTERN_PLUS) {
          trunk.write(pattern.current);
          pattern.moveNext();
          format._useSignForPositiveExponent = true;
        }

        // Use lookahead to parse out the exponential part
        // of the pattern, then jump into phase 2.
        while (pattern.current == _PATTERN_ZERO_DIGIT) {
          trunk.write(pattern.current);
          pattern.moveNext();
          format.minimumExponentDigits++;
        }

        if ((digitLeftCount + zeroDigitCount) < 1 ||
            format.minimumExponentDigits < 1) {
          throw new FormatException(
              'Malformed exponential pattern "$pattern"');
        }
        return false;
      default:
        return false;
    }
    trunk.write(ch);
    pattern.moveNext();
    return true;
  }
}

/**
 * Returns an [Iterable] on the string as a list of substrings.
 */
Iterable _iterable(String s) => new _StringIterable(s);

/**
 * Return an iterator on the string as a list of substrings.
 */
Iterator _iterator(String s) => new _StringIterator(s);

// TODO(nweiz): remove this when issue 3780 is fixed.
/**
 * Provides an Iterable that wraps [_iterator] so it can be used in a `for`
 * loop.
 */
class _StringIterable extends IterableBase<String> {
  final Iterator<String> iterator;

  _StringIterable(String s)
      : iterator = _iterator(s);
}

/**
 * Provides an iterator over a string as a list of substrings, and also
 * gives us a lookahead of one via the [peek] method.
 */
class _StringIterator implements Iterator<String> {
  String input;
  var index = -1;
  inBounds(i) => i >= 0 && i < input.length;
  _StringIterator(this.input);
  String get current => inBounds(index) ? input[index] : null;

  bool moveNext() => inBounds(++index);
  String get peek => inBounds(index + 1) ? input[index + 1] : null;
  Iterator<String> get iterator => this;
}
part of angular.mock;

class _MockXhr {
  var $$method, $$url, $$async, $$reqHeaders, $$respHeaders;

  open(method, url, async) {
    $$method = method;
    $$url = url;
    $$async = async;
    $$reqHeaders = {};
    $$respHeaders = {};
  }

  var $$data;

  send(data) {
    $$data = data;
  }

  setRequestHeader(key, value) {
    $$reqHeaders[key] = value;
  }

  getResponseHeader(name) {
    // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
    if ($$respHeaders.containsKey(name)) {
      return $$respHeaders[name];
    }

    name = name.toLowerCase();
    if ($$respHeaders.containsKey(name)) {
      return $$respHeaders[name];
    }

    String header = null;
    $$respHeaders.forEach((headerName, headerVal) {
      if (header != null) return;
      if (headerName.toLowerCase()) header = headerVal;
    });
    return header;
  }

  getAllResponseHeaders() {
    if ($$respHeaders == null) return '';

    var lines = [];

    $$respHeaders.forEach((key, value) {
      lines.add("$key: $value");
    });
    return lines.join('\n');
  }

  // noop
  abort() {}
}

/**
 * An internal class used by [MockHttpBackend].
 */
class MockHttpExpectation {

  var method, url, data, headers;

  var response;

  MockHttpExpectation(this.method, this.url, [this.data, this.headers]);

  match(m, u, [d, h]) {
    if (method != m) return false;
    if (!matchUrl(u)) return false;
    if (d != null && !matchData(d)) return false;
    if (h != null && !matchHeaders(h)) return false;
    return true;
  }

  matchUrl(u) {
    if (url == null) return true;
    if (url is RegExp) return url.hasMatch(u);
    return url == u;
  }

  matchHeaders(h) {
    if (headers == null) return true;
    if (headers is Function) return headers(h);
    return "$headers" == "$h";
  }

  matchData(d) {
    if (data == null) return true;
    if (d == null) return false; // data is not null, but d is.
    if (data is File) return data == d;
    assert(d is String);
    if (data is RegExp) return data.hasMatch(d);
    return json.stringify(data) == json.stringify(d);
  }

  toString() {
    return "$method $url";
  }
}


class _Chain {
  var _respondFn;
  _Chain({respond}) {
    _respondFn = respond;
  }
  respond([x,y,z]) => _respondFn(x,y,z);
}

/**
 * A mock implementation of [HttpBackend], used in tests.
 */
class MockHttpBackend implements HttpBackend {
  var definitions = [],
      expectations = [],
      responses = [];

  /**
   * This function is called from [Http] and designed to mimic the Dart APIs.
   */
  Future request(String url,
                 {String method, bool withCredentials, String responseType,
                 String mimeType, Map<String, String> requestHeaders, sendData,
                 void onProgress(ProgressEvent e)}) {
    Completer c = new Completer();
    var callback = (status, data, headers) {
      if (status >= 200 && status < 300) {
        c.complete(new MockHttpRequest(status, data, headers));
      } else {
        c.completeError(
            new MockProgressEvent(
                new MockHttpRequest(status, data, headers)));
      }
    };
    call(method == null ? 'GET' : method, url, sendData, callback, requestHeaders);
    return c.future;
  }

  _createResponse(status, data, headers) {
    if (status is Function) return status;

    return ([a,b,c,d,e]) {
      return status is num
          ? [status, data, headers]
          : [200, status, data];
    };
  }


 /**
  * A callback oriented API.  This function takes a callback with
  * will be called with (status, data, headers)
  */
  call(method, [url, data, callback, headers, timeout]) {
    var xhr = new _MockXhr(),
        expectation = expectations.isEmpty ? null : expectations[0],
        wasExpected = false;

    var prettyPrint = (data) {
      return (data is String || data is Function || data is RegExp)
          ? data
          : json.stringify(data);
    };

    var wrapResponse = (wrapped) {
      var handleResponse = () {
        var response = wrapped.response(method, url, data, headers);
        xhr.$$respHeaders = response[2];
        utils.relaxFnApply(callback, [response[0], response[1], xhr.getAllResponseHeaders()]);
      };

      var handleTimeout = () {
        for (var i = 0, ii = responses.length; i < ii; i++) {
          if (identical(responses[i], handleResponse)) {
            responses.removeAt(i);
            callback(-1, null, '');
            break;
          }
        }
      };

      if (timeout != null) timeout.then(handleTimeout);
      return handleResponse;
    };

    if (expectation != null && expectation.match(method, url)) {
      if (!expectation.matchData(data))
        throw ['Expected $expectation with different data\n' +
            'EXPECTED: ${prettyPrint(expectation.data)}\nGOT:      $data'];

      if (!expectation.matchHeaders(headers))
        throw ['Expected $expectation with different headers\n' +
            'EXPECTED: ${prettyPrint(expectation.headers)}\nGOT:      ${prettyPrint(headers)}'];

      expectations.removeAt(0);

      if (expectation.response != null) {
        responses.add(wrapResponse(expectation));
        return;
      }
      wasExpected = true;
    }

    for (var definition in definitions) {
      if (definition.match(method, url, data, headers != null ? headers : {})) {
        if (definition.response != null) {
          // if $browser specified, we do auto flush all requests
          responses.add(wrapResponse(definition));
        } else throw ['No response defined !'];
        return;
      }
    }
    throw wasExpected ?
        ['No response defined !'] :
        ['Unexpected request: $method $url\n' +
            (expectation != null ? 'Expected $expectation' : 'No more requests expected')];
  }

  /**
   * Creates a new backend definition.
   *
   * @param {string} method HTTP method.
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
   *   object and returns true if the headers match the current definition.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   *
   *  - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
   *    – The respond method takes a set of static data to be returned or a function that can return
   *    an array containing response status (number), response data (string) and response headers
   *    (Object).
   */
  when(method, [url, data, headers]) {
    var definition = new MockHttpExpectation(method, url, data, headers),
        chain = new _Chain(respond: (status, data, headers) {
            definition.response = _createResponse(status, data, headers);
          });

    definitions.add(definition);
    return chain;
  }

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenGET
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for GET requests. For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(Object|function(Object))=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */


  whenGET(url, [headers]) =>
  when('GET', url, null, headers);
  whenDELETE(url, [headers]) =>
  when('DELETE', url, null, headers);
  whenJSONP(url, [headers]) =>
  when('JSONP', url, null, headers);

  whenPUT(url, [data, headers]) =>
  when('PUT', url, data, headers);
  whenPOST(url, [data, headers]) =>
  when('POST', url, data, headers);
  whenPATCH(url, [data, headers]) =>
  when('PATCH', url, data, headers);

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenHEAD
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for HEAD requests. For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(Object|function(Object))=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenDELETE
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for DELETE requests. For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(Object|function(Object))=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenPOST
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for POST requests. For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {(Object|function(Object))=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenPUT
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for PUT requests.  For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {(Object|function(Object))=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#whenJSONP
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new backend definition for JSONP requests. For more info see `when()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled.
   */
  //createShortMethods('when');


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expect
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation.
   *
   * @param {string} method HTTP method.
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
   *   object and returns true if the headers match the current expectation.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *  request is handled.
   *
   *  - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
   *    – The respond method takes a set of static data to be returned or a function that can return
   *    an array containing response status (number), response data (string) and response headers
   *    (Object).
   */
  expect(method, [url, data, headers]) {
    var expectation = new MockHttpExpectation(method, url, data, headers);
    expectations.add(expectation);
    return new _Chain(respond: (status, data, headers) {
        expectation.response = _createResponse(status, data, headers);
      });
  }


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectGET
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for GET requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   * request is handled. See #expect for more info.
   */
  expectGET(url, [headers]) =>
  expect('GET', url, null, headers);
  expectDELETE(url, [headers]) =>
  expect('DELETE', url, null, headers);
  expectJSONP(url, [headers]) =>
  expect('JSONP', url, null, headers);

  expectPUT(url, [data, headers]) =>
  expect('PUT', url, data, headers);
  expectPOST(url, [data, headers]) =>
  expect('POST', url, data, headers);
  expectPATCH(url, [data, headers]) =>
  expect('PATCH', url, data, headers);

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectHEAD
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for HEAD requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectDELETE
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for DELETE requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectPOST
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for POST requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectPUT
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for PUT requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectPATCH
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for PATCH requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @param {(string|RegExp)=} data HTTP request body.
   * @param {Object=} headers HTTP headers.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */

  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#expectJSONP
   * @methodOf ngMock.$httpBackend
   * @description
   * Creates a new request expectation for JSONP requests. For more info see `expect()`.
   *
   * @param {string|RegExp} url HTTP url.
   * @returns {requestHandler} Returns an object with `respond` method that control how a matched
   *   request is handled.
   */
  //createShortMethods('expect');


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#flush
   * @methodOf ngMock.$httpBackend
   * @description
   * Flushes all pending requests using the trained responses.
   *
   * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
   *   all pending requests will be flushed. If there are no pending requests when the flush method
   *   is called an exception is thrown (as this typically a sign of programming error).
   */
  flush([count]) {
    if (responses.isEmpty) throw ['No pending request to flush !'];

    if (count != null) {
      while (count-- > 0) {
        if (responses.isEmpty) throw ['No more pending request to flush !'];
        responses.removeAt(0)();
      }
    } else {
      while (!responses.isEmpty) {
        responses.removeAt(0)();
      }
    }
    verifyNoOutstandingExpectation();
  }


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
   * @methodOf ngMock.$httpBackend
   * @description
   * Verifies that all of the requests defined via the `expect` api were made. If any of the
   * requests were not made, verifyNoOutstandingExpectation throws an exception.
   *
   * Typically, you would call this method following each test case that asserts requests using an
   * "afterEach" clause.
   *
   * <pre>
   *   afterEach($httpBackend.verifyNoOutstandingExpectation);
   * </pre>
   */
  verifyNoOutstandingExpectation() {
    if (!expectations.isEmpty) {
      throw ['Unsatisfied requests: ${expectations.join(', ')}'];
    }
  }


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#verifyNoOutstandingRequest
   * @methodOf ngMock.$httpBackend
   * @description
   * Verifies that there are no outstanding requests that need to be flushed.
   *
   * Typically, you would call this method following each test case that asserts requests using an
   * "afterEach" clause.
   *
   * <pre>
   *   afterEach($httpBackend.verifyNoOutstandingRequest);
   * </pre>
   */
  verifyNoOutstandingRequest() {
    if (!responses.isEmpty) {
      throw ['Unflushed requests: ${responses.length}'];
    }
  }


  /**
   * @ngdoc method
   * @name ngMock.$httpBackend#resetExpectations
   * @methodOf ngMock.$httpBackend
   * @description
   * Resets all request expectations, but preserves all backend definitions. Typically, you would
   * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
   * $httpBackend mock.
   */
  resetExpectations() {
    expectations.length = 0;
    responses.length = 0;
  }
}

/**
 * Mock implementation of the [HttpRequest] object returned from the HttpBackend.
 */
class MockHttpRequest implements HttpRequest {
  final bool supportsCrossOrigin = false;
  final bool supportsLoadEndEvent = false;
  final bool supportsOverrideMimeType = false;
  final bool supportsProgressEvent = false;
  final Events on = null;

  final Stream<ProgressEvent> onAbort = null;
  final Stream<ProgressEvent> onError = null;
  final Stream<ProgressEvent> onLoad = null;
  final Stream<ProgressEvent> onLoadEnd = null;
  final Stream<ProgressEvent> onLoadStart = null;
  final Stream<ProgressEvent> onProgress = null;
  final Stream<ProgressEvent> onReadyStateChange = null;

  final Stream<ProgressEvent> onTimeout = null;
  final int readyState = 0;

  get responseText => response == null ? null : "$response";
  final responseXml = null;
  final String statusText = null;
  final HttpRequestUpload upload = null;

  String responseType = null;
  int timeout = 0;
  bool withCredentials;

  final int status;
  final response;
  final String headers;

  MockHttpRequest(int this.status, String this.response, [this.headers]);

  void abort() {}
  bool dispatchEvent(Event event) => false;
  String getAllResponseHeaders() {
    if (headers == null) return null;
    return headers;
  }
  String getResponseHeader(String header) => null;

  void open(String method, String url, {bool async, String user, String password}) {}
  void overrideMimeType(String override) {}
  void send([data]) {}
  void setRequestHeader(String header, String value) {}
  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) {}
  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) {}
}

class MockProgressEvent implements ProgressEvent {
  final bool bubbles = false;
  final bool cancelable = false;
  final DataTransfer clipboardData = null;
  final EventTarget currentTarget;
  final bool defaultPrevented = false;
  final int eventPhase = 0;
  final bool lengthComputable = false;
  final int loaded = 0;
  final List<Node> path = null;
  final int position = 0;
  final Type runtimeType = null;
  final EventTarget target = null;
  final int timeStamp = 0;
  final int total = 0;
  final int totalSize = 0;
  final String type = null;

  bool cancelBubble = false;

  MockProgressEvent(MockHttpRequest this.currentTarget);

  void preventDefault() {}
  void stopImmediatePropagation() {}
  void stopPropagation() {}
}
library angular.io_impl;

import 'dart:io';
import 'io.dart';

class IoServiceImpl implements IoService {

  String readAsStringSync(String filePath) =>
      new File(filePath).readAsStringSync();

  void visitFs(String rootDir, FsVisitor visitor) {
    Directory root = new Directory(rootDir);
    if (!FileSystemEntity.isDirectorySync(rootDir)) {
      throw 'Expected $rootDir to be a directory!';
    }
    root.listSync(recursive: true, followLinks: true).forEach((entity) {
      if (entity.statSync().type == FileSystemEntityType.FILE) {
        visitor(entity.path);
      }
    });
  }
}
part of angular.directive;

/**
 * The ngBind attribute tells Angular to replace the text content of the
 * specified HTML element with the value of a given expression, and to update
 * the text content when the value of that expression changes.
 *
 * Typically, you don't use ngBind directly, but instead you use the double
 * curly markup like {{ expression }} which is similar but less verbose.
 *
 * It is preferrable to use ngBind instead of {{ expression }} when a template
 * is momentarily displayed by the browser in its raw state before Angular
 * compiles it. Since ngBind is an element attribute, it makes the bindings
 * invisible to the user while the page is loading.
 *
 * An alternative solution to this problem would be using the ngCloak directive.
 */
@NgDirective(
  selector: '[ng-bind]',
  map: const {'ng-bind': '=.value'})
class NgBindDirective {
  dom.Element element;

  NgBindDirective(dom.Element this.element);

  set value(value) => element.text = value == null ? '' : value.toString();
}
library angular;

export 'bootstrap.dart';
export 'core/module.dart';
export 'core_dom/module.dart';
export 'core/parser/parser_library.dart';
export 'directive/module.dart';
export 'filter/module.dart';
part of angular.core;

typedef void ZoneOnTurn();
typedef void ZoneOnError(dynamic error, dynamic stacktrace, LongStackTrace longStacktrace);

/**
 * Contains the locations of runAsync calls across VM turns.
 */
class LongStackTrace {
  final String reason;
  final dynamic stacktrace;
  final LongStackTrace parent;

  LongStackTrace(this.reason, this.stacktrace, this.parent);

  toString() {
    List<String> frames = '${this.stacktrace}'.split('\n');
    frames = frames.where((frame) {
      return frame.indexOf('(dart:') == -1 && // skip dart runtime libs
             frame.indexOf('(package:angular/zone.dart') == -1; // skip angular zone
    }).toList();
    frames.insert(0, reason);
    var parent = this.parent == null ? '' : this.parent;
    return '${frames.join("\n    ")}\n$parent';
  }
}

/**
 * A better zone API which implements onTurnDone.
 */
class Zone {
  Zone() {
    _zone = async.Zone.current.fork(specification: new async.ZoneSpecification(
        run: _onRun,
        runUnary: _onRunUnary,
        scheduleMicrotask: _onScheduleMicrotask,
        handleUncaughtError: _uncaughtError
    ));
  }

  async.Zone _zone;

  List _asyncQueue = [];
  bool _errorThrownFromOnRun = false;

  _onRunBase(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) {
    _runningInTurn++;
    try {
      return fn();
    } catch (e, s) {
      onError(e, s, _longStacktrace);
      _errorThrownFromOnRun = true;
      rethrow;
    } finally {
      _runningInTurn--;
      if (_runningInTurn == 0)
        _finishTurn(zone, delegate);
    }
  }
  // Called from the parent zone.
  _onRun(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) {
    return _onRunBase(self, delegate, zone, () => delegate.run(zone, fn));
  }

  _onRunUnary(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn(args), args) {
    return _onRunBase(self, delegate, zone, () => delegate.runUnary(zone, fn, args));
  }

  _onScheduleMicrotask(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) {
    _asyncQueue.add(() => delegate.run(zone, fn));
    if (_runningInTurn == 0 && !_inFinishTurn) {
      _finishTurn(zone, delegate);
    }
  }

  _uncaughtError(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, e) {
    if (!_errorThrownFromOnRun) {
      onError(e, async.getAttachedStackTrace(e), _longStacktrace);
    }
    _errorThrownFromOnRun = false;
  }

  var _inFinishTurn = false;
  _finishTurn(zone, delegate) {
    if (_inFinishTurn) {
      return;
    }
    _inFinishTurn = true;
    try {
      // Two loops here: the inner one runs all queued microtasks,
      // the outer runs onTurnDone (e.g. scope.$digest) and then
      // any microtasks which may have been queued from onTurnDone.
      do {
        while (!_asyncQueue.isEmpty) {
          delegate.run(zone, _asyncQueue.removeAt(0));
        }
        delegate.run(zone, onTurnDone);
      } while (!_asyncQueue.isEmpty);
    } catch (e, s) {
      onError(e, s, _longStacktrace);
      _errorThrownFromOnRun = true;
      rethrow;
    } finally {
    _inFinishTurn = false;
    }
  }

  int _runningInTurn = 0;

  /**
   * A function called with any errors from the zone.
   */
  var onError = (e, s, ls) => null;

  /**
   * A function that is called at the end of each VM turn in which the
   * in-zone code or any runAsync callbacks were run.
   */
  var onTurnDone = () => null;  // Type was ZoneOnTurn: dartbug 13519

  /**
   * A function that is called when uncaught errors are thrown inside the zone.
   */
  // var onError = (dynamic e, dynamic s, LongStackTrace ls) => print('EXCEPTION: $e\n$s\n$ls');
  // Type was ZoneOnError: dartbug 13519

  LongStackTrace _longStacktrace = null;

  LongStackTrace _getLongStacktrace(name) {
    var shortStacktrace = 'Long-stacktraces supressed in production.';
    assert((shortStacktrace = _getStacktrace()) != null);
    return new LongStackTrace(name, shortStacktrace, _longStacktrace);
  }

  _getStacktrace() {
    try { throw []; } catch (e, s) {
      return s;
    }
  }

  /**
   * Runs the provided function in the zone.  Any runAsync calls (e.g. futures)
   * will also be run in this zone.
   *
   * Returns the return value of body.
   */
  run(body()) {
    return _zone.run(body);
  }

  assertInTurn() {
    assert(_runningInTurn > 0 || _inFinishTurn);
  }

  assertInZone() {
    assertInTurn();
  }
}
part of angular.filter;

// Too bad you can't stick typedef's inside a class.
typedef bool Predicate(e);
typedef bool Equals(a, b);

/**
 * Selects a subset of items from the provided [List] and returns it as a new
 * [List].
 *
 * In addition to the input list (implicit in an Angular expression syntax),
 * this filter takes 1 required and 1 optional parameter.  They are:
 *
 * - `expression` (required) - one of [Map], [Function], [String], [bool], [num]
 * - `comparator` (optional)
 * 
 * <br>
 * 
 * # expression
 * 
 * can be one of:
 * 
 * - [String], [bool] and [num]:  Only items in the List that directly
 *   match this expression, items that are Maps with any value matching this
 *   item and items that are Lists containing a matching items are returned.
 * 
 * - [Map]:  This defines a pattern map.  Filters specific properties on objects contained
 *   in the input List.  For example `{name:"M", phone:"1"}` predicate will
 *   return a list of items which have property `name` containing "M" and
 *   property `phone` containing "1".  A special property name, `$`, can be used
 *   (as in `{$: "text"}`) to accept a match against any property of the object.
 *   That's equivalent to the simple substring match with a `String` as
 *   described above.
 * 
 * - [Function]:  This allows you to supply a custom function to filter the
 *   List.  The function is called for each element of the List.  The returned
 *   List contains exactly those elements for which this function returned
 *   `true`.
 * 
 * <br>
 *
 * # comparator
 * 
 * can be one of:
 * 
 * - `bool comparator(expected, actual)`:  The function will be called with the
 *   object value and the predicate value to compare and should return true if the
 *   item should be included in filtered result.
 *
 * - `true`:  Specifies that only identical objects matching the expression
 *   exactly should be considered matches.  Two strings are considered identical
 *   if they are equal.  Two numbers are considered identical if they are either
 *   equal or both are `NaN`.  All other objects are identical iff
 *   identical(expected, actual) is true.
 *
 * - `false|null`:  Specifies case insensitive substring matching.
 * 
 * <br>
 *
 * # Example:
 * 
 *     // main.dart
 *     import 'package:angular/angular.dart';
 * 
 *     @NgDirective(selector: '[toy-data]')
 *     class ToyData {
 *       ToyData(Scope scope) {
 *         scope.friends = [{name:'John', phone:'555-1276'},
 *                          {name:'Mary', phone:'800-BIG-MARY'},
 *                          {name:'Mike', phone:'555-4321'},
 *                          {name:'Adam', phone:'555-5678'},
 *                          {name:'Julie', phone:'555-8765'},
 *                          {name:'Juliette', phone:'555-5678'}];
 *       }
 *     }
 *
 *     main() {
 *       bootstrapAngular([new AngularModule()..type(ToyData)], 'html');
 *     }
 *
 * and
 *
 *     <!-- index.html -->
 *     <html>
 *       <head>
 *         <script src="packages/browser/dart.js"></script>
 *         <script src="main.dart" type="application/dart"></script>
 *       </head>
 *       <body toy-data>
 *         Search: <input ng-model="searchText">
 *         <table id="searchTextResults">
 *           <tr><th>Name</th><th>Phone</th></tr>
 *           <tr ng-repeat="friend in friends | filter:searchText">
 *             <td>{{friend.name}}</td>
 *             <td>{{friend.phone}}</td>
 *           </tr>
 *         </table>
 *         <hr>
 *         Any: <input ng-model="search.$"> <br>
 *         Name only <input ng-model="search.name"><br>
 *         Phone only <input ng-model="search.phone"><br>
 *         Equality <input type="checkbox" ng-model="strict"><br>
 *         <table id="searchObjResults">
 *           <tr><th>Name</th><th>Phone</th></tr>
 *           <tr ng-repeat="friend in friends | filter:search:strict">
 *             <td>{{friend.name}}</td>
 *             <td>{{friend.phone}}</td>
 *           </tr>
 *         </table>
 *       </body>
 *     </html>
 */
@NgFilter(name: 'filter')
class FilterFilter {
  Parser _parser;
  Equals _comparator;

  FilterFilter(Parser this._parser);

  static _nop(e) => e;

  static _ensureBool(val) => (val is bool && val);

  static _isSubstringCaseInsensitive(String a, String b) =>
      a != null && b != null && a.toLowerCase().contains(b.toLowerCase());

  static _identical(a, b) => identical(a, b) ||
                      (a is String && b is String && a == b) ||
                      (a is num && b is num && a.isNaN && b.isNaN);

  // Used by _defaultComparator to compare strings.
  Equals _stringComparator;

  Equals _configureComparator(var comparatorExpression) {
    if (comparatorExpression == null || comparatorExpression == false) {
      _stringComparator = _isSubstringCaseInsensitive;
      _comparator = _defaultComparator;
    } else if (comparatorExpression == true) {
      _stringComparator = _identical;
      _comparator = _defaultComparator;
    } else if (comparatorExpression is Equals) {
      _comparator = (a, b) => _ensureBool(comparatorExpression(a, b));
    } else {
      _comparator = null;
    }
  }

  // Preconditions
  // - what: NOT a Map
  // - item: neither a Map nor a List
  bool _defaultComparator(var item, var what) {
    if (what == null) {
      return false;
    } else if (item == null) {
      return what == '';
    }
    if (what is String && what.startsWith('!')) {
      return !_search(item, what.substring(1));
    }
    if (item is String) {
      return (what is String) && _stringComparator(item, what);
    } else if (item is bool) {
      if (what is bool) {
        return item == what;
      } else if (what is String) {
        what = (what as String).toLowerCase();
        // TODO(chirayu): Support this extension?  Yes => add tests.
        return item ? (what == "true"  || what == "yes" || what == "on")
                    : (what == "false" || what == "no"  || what == "off");
      } else {
        return false;
      }
    } else if (item is num) {
      if (what is num) {
        return item == what || (item.isNaN && what.isNaN);
      } else {
        // TODO(chirayu): I think this expression is more appropriate here.
        //
        // return what is String && '$item' == what;
        return what is String && _stringComparator('$item', what);
      }
    } else {
      return false; // Unsupported item type.
    }
  }

  bool _search(var item, var what) {
    if (what is Map) {
      return what.keys.every((key) {
        return _search((key == r'$') ? item : _parser(key).eval(item, null),
                       what[key]);
      });
    } else {
      if (item is Map) {
        return item.keys.any((k) => !k.startsWith(r'$') && _search(item[k], what));
      } else if (item is List) {
        return item.any((i) => _search(i, what));
      } else {
        return _comparator(item, what);
      }
    }
  }

  Predicate _toPredicate(var expression) {
    if (expression is Predicate) {
      return (item) => _ensureBool(expression(item));
    } else if (_comparator == null) {
      return (item) => false; // Bad comparator → no items for you!
    } else {
      return (item) => _search(item, expression);
    }
  }

  List call(List items, var expression, [var comparator]) {
    if (expression == null) {
      return items.toList(); // Missing expression → passthrough.
    } else if (expression is! Map && expression is! Function &&
               expression is! String && expression is! bool && expression is! num) {
      return const []; // Bad expression → no items for you!
    }
    _configureComparator(comparator);
    // TODO(chirayu): Important to set _comparator=null before return?
    return items.where(_toPredicate(expression)).toList();
  }
}
library angular.core;

import 'dart:async' as async;
import 'dart:collection';
import 'dart:json';
import 'dart:mirrors';

import 'package:di/di.dart';
import 'package:perf_api/perf_api.dart';
import 'package:meta/meta.dart';

import 'parser/parser_library.dart';
import '../utils.dart';


part "cache.dart";
part "directive.dart";
part "exception_handler.dart";
part "filter.dart";
part "interpolate.dart";
part "registry.dart";
part "scope.dart";
part "zone.dart";


class NgCoreModule extends Module {
  NgCoreModule() {
    type(ScopeDigestTTL);

    type(MetadataExtractor);
    type(Cache);
    type(DirectiveMap);
    type(ExceptionHandler);
    type(FilterMap);
    type(Interpolate);
    type(Scope);
    type(Zone);

    type(Parser, implementedBy: DynamicParser);
    type(DynamicParser);
    type(Lexer);
    type(ParserBackend);
    type(GetterSetter);
  }
}
library angular.bootstrap;

import 'dart:html' as dom;
import 'package:di/di.dart';
import 'package:di/dynamic_injector.dart';
import 'package:perf_api/perf_api.dart';

import 'core/module.dart';
import 'core_dom/module.dart';
import 'directive/module.dart';
import 'filter/module.dart';
import 'perf/module.dart';

/**
 * This is the top level module which describes the whole of angular.
 *
 * The Module is made up or
 *
 * - [NgCoreModule]
 * - [NgCoreDomModule]
 * - [NgFilterModule]
 * - [NgPerfModule]
 */
class AngularModule extends Module {
  AngularModule() {
    install(new NgCoreModule());
    install(new NgCoreDomModule());
    install(new NgDirectiveModule());
    install(new NgFilterModule());
    install(new NgPerfModule());
  }
}

Injector _defaultInjectorFactory(List<Module> modules) =>
    new DynamicInjector(modules: modules);

// helper for bootstrapping angular
bootstrapAngular(modules, [rootElementSelector = '[ng-app]',
    Injector injectorFactory(List<Module> modules) = _defaultInjectorFactory]) {
  var allModules = new List.from(modules);
  List<dom.Node> topElt = dom.query(rootElementSelector).nodes.toList();
  assert(topElt.length > 0);

  // The injector must be created inside the zone, so we create the
  // zone manually and give it back to the injector as a value.
  Zone zone = new Zone();
  allModules.add(new Module()..value(Zone, zone));

  return zone.run(() {
    Injector injector = injectorFactory(allModules);
    injector.get(Compiler)(topElt)(injector, topElt);
    return injector;
  });
}

part of angular.filter;

/**
 * Formats a number as a currency (ie $1,234.56). When no currency symbol is
 * provided, '$' used.
 *
 *
 * Usage:
 *
 *     {{ number_expression | number[:fractionSize] }}
 *
 */
@NgFilter(name:'currency')
class CurrencyFilter {

  NumberFormat nf = new NumberFormat();

  CurrencyFilter() {
    nf.minimumFractionDigits = 2;
    nf.maximumFractionDigits = 2;
  }

  /**
   *  [value]: the value to format
   *
   *  [symbol]: Symbol to use.
   *
   *  [leading]: Symbol should be placed in front of the number
   */
  call(value, [symbol = r'$', leading = true]) {
    if (value is String) value = double.parse(value);
    if (!(value is num)) return value;
    if (value.isNaN) return '';
    var neg = value < 0;
    if (neg) value = -value;
    var before = neg ? '(' : '';
    var after = neg ? ')' : '';
    if (leading) {
      return '$before$symbol${nf.format(value)}$after';
    } else {
      return '$before${nf.format(value)}$symbol$after';
    }
  }
}
part of angular.directive;

class _Row {
  var id;
  Scope scope;
  Block block;
  dom.Element startNode;
  dom.Element endNode;
  List<dom.Element> elements;

  _Row(this.id);
}

/**
 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
 * instance gets its own scope, where the given loop variable is set to the current collection item,
 * and `$index` is set to the item index or key.
 *
 * Special properties are exposed on the local scope of each template instance, including:
 *
 * <table>
 * <tr><th> Variable  </th><th> Type  </th><th> Details                                                                     <th></tr>
 * <tr><td> `$index`  </td><td>[num] </td><td> iterator offset of the repeated element (0..length-1)                       <td></tr>
 * <tr><td> `$first`  </td><td>[bool]</td><td> true if the repeated element is first in the iterator.                      <td></tr>
 * <tr><td> `$middle` </td><td>[bool]</td><td> true if the repeated element is between the first and last in the iterator. <td></tr>
 * <tr><td> `$last`   </td><td>[bool]</td><td> true if the repeated element is last in the iterator.                       <td></tr>
 * <tr><td> `$even`   </td><td>[bool]</td><td> true if the iterator position `$index` is even (otherwise false).           <td></tr>
 * <tr><td> `$odd`    </td><td>[bool]</td><td> true if the iterator position `$index` is odd (otherwise false).            <td></tr>
 * </table>
 *
 *
 * [repeat_expression] ngRepeat The expression indicating how to enumerate a collection. These
 *   formats are currently supported:
 *
 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
 *     is a scope expression giving the collection to enumerate.
 *
 *     For example: `album in artist.albums`.
 *
 *   * `variable in expression track by tracking_expression` – You can also provide an optional
 *     tracking function which can be used to associate the objects in the collection with the DOM
 *     elements. If no tracking function is specified the ng-repeat associates elements by identity
 *     in the collection. It is an error to have more than one tracking function to resolve to the
 *     same key. (This would mean that two distinct objects are mapped to the same DOM element,
 *     which is not possible.)  Filters should be applied to the expression, before specifying a
 *     tracking expression.
 *
 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This
 *     implies that the DOM elements will be associated by item identity in the array.
 *
 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used
 *     to assign a unique `$$hashKey` property to each item in the array. This property is then
 *     used as a key to associated DOM elements with the corresponding item in the array by
 *     identity. Moving the same object in array would move the DOM element in the same way ian the
 *     DOM.
 *
 *     For example: `item in items track by item.id` is a typical pattern when the items come from
 *     the database. In this case the object identity does not matter. Two objects are considered
 *     equivalent as long as their `id` property is same.
 *
 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be
 *     used to apply a filter to items in conjunction with a tracking expression.
 *
 *
 * # Example:
 *
 *     <ul ng-repeat="item in ['foo', 'bar', 'baz']">
 *       <li>{{$item}}</li>
 *     </ul>
 */

@NgDirective(
    children: NgAnnotation.TRANSCLUDE_CHILDREN,
    selector: '[ng-repeat]',
    map: const {'.': '@.expression'})
class NgRepeatDirective  {
  static RegExp _SYNTAX = new RegExp(r'^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$');
  static RegExp _LHS_SYNTAX = new RegExp(r'^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$');

  BlockHole _blockHole;
  BoundBlockFactory _boundBlockFactory;
  Scope _scope;

  String _expression;
  String _valueIdentifier;
  String _keyIdentifier;
  String _listExpr;
  Map<Object, _Row> _rows = new Map<dynamic, _Row>();
  Function _trackByIdFn = (key, value, index) => value;
  Function _removeWatch = () => null;

  NgRepeatDirective(BlockHole this._blockHole,
                    BoundBlockFactory this._boundBlockFactory,
                    Scope this._scope);

  set expression(value) {
    _expression = value;
    _removeWatch();
    Match match = _SYNTAX.firstMatch(_expression);
    if (match == null) {
      throw "[NgErr7] ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '$_expression'.";
    }
    _listExpr = match.group(2);
    var assignExpr = match.group(1);
    match = _LHS_SYNTAX.firstMatch(assignExpr);
    if (match == null) {
      throw "[NgErr8] ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '$assignExpr'.";
    }
    _valueIdentifier = match.group(3);
    if (_valueIdentifier == null) _valueIdentifier = match.group(1);
    _keyIdentifier = match.group(2);

    _removeWatch = _scope.$watchCollection(_listExpr, _onCollectionChange);
  }

  List<_Row> _computeNewRows(collection, trackById) {
    List<_Row> newRowOrder = [];
    // Same as lastBlockMap but it has the current state. It will become the
    // lastBlockMap on the next iteration.
    Map<dynamic, _Row> newRows = new Map<dynamic, _Row>();
    var arrayLength = collection.length;
    // locate existing items
    var length = newRowOrder.length = collection.length;
    for (var index = 0; index < length; index++) {
      var value = collection[index];
      trackById = _trackByIdFn(index, value, index);
      if (_rows.containsKey(trackById)) {
        var row = _rows[trackById];
        _rows.remove(trackById);
        newRows[trackById] = row;
        newRowOrder[index] = row;
      } else if (newRows.containsKey(trackById)) {
        // restore lastBlockMap
        newRowOrder.forEach((row) {
          if (row != null && row.startNode != null) {
            _rows[row.id] = row;
          }
        });
        // This is a duplicate and we need to throw an error
        throw "[NgErr50] ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: $_expression, Duplicate key: $trackById";
      } else {
        // new never before seen row
        newRowOrder[index] = new _Row(trackById);
        newRows[trackById] = null;
      }
    }
    // remove existing items
    _rows.forEach((key, row){
      row.block.remove();
      row.scope.$destroy();
    });
    _rows = newRows;
    return newRowOrder;
  }

  _onCollectionChange(collection) {
    var previousNode = _blockHole.elements[0],     // current position of the node
        nextNode,
        childScope,
        trackById,
        cursor = _blockHole;

    if (collection is! List) {
      collection = [];
    }

    List<_Row> newRowOrder = _computeNewRows(collection, trackById);

    for (var index = 0, length = collection.length; index < length; index++) {
      var key = index;
      var value = collection[index];
      _Row row = newRowOrder[index];

      if (row.startNode != null) {
        // if we have already seen this object, then we need to reuse the
        // associated scope/element
        childScope = row.scope;

        nextNode = previousNode;
        do {
          nextNode = nextNode.nextNode;
        } while(nextNode != null);

        if (row.startNode == nextNode) {
          // do nothing
        } else {
          // existing item which got moved
          row.block.moveAfter(cursor);
        }
        previousNode = row.endNode;
      } else {
        // new item which we don't know about
        childScope = _scope.$new();
      }

      childScope[_valueIdentifier] = value;
      childScope[r'$index'] = index;
      childScope[r'$first'] = (index == 0);
      childScope[r'$last'] = (index == (collection.length - 1));
      childScope[r'$middle'] = !(childScope.$first || childScope.$last);
      childScope[r'$odd'] = index & 1 == 1;
      childScope[r'$even'] = index & 1 == 0;

      if (row.startNode == null) {
        _rows[row.id] = row;
        var block = _boundBlockFactory(childScope);
        row.block = block;
        row.scope = childScope;
        row.elements = block.elements;
        row.startNode = row.elements[0];
        row.endNode = row.elements[row.elements.length - 1];
        block.insertAfter(cursor);
      }
      cursor = row.block;
    }
  }
}
part of angular.filter;

/**
 * Converts string to lowercase.
 *
 * Usage:
 *
 *     {{ lowercase_expression | lowercase }}
 */
@NgFilter(name:'lowercase')
class LowercaseFilter {
  call(String text) => text == null ? text : text.toLowerCase();
}
part of angular.core;

class NgAnnotation {
  /**
   * CSS selector which will trigger this component/directive.
   * CSS Selectors are limited to a single element and can contain:
   *
   * * `element-name` limit to a given element name.
   * * `.class` limit to an element with a given class.
   * * `[attribute]` limit to an element with a given attribute name.
   * * `[attribute=value]` limit to an element with a given attribute and value.
   *
   *
   * Example: `input[type=checkbox][ng-model]`
   */
  final String selector;

  /**
   * Specifies the compiler action to be taken on the child nodes of the
   * element which this currently being compiled.  The values are:
   *
   * * [COMPILE_CHILDREN] (*default*)
   * * [TRANSCLUDE_CHILDREN]
   * * [IGNORE_CHILDREN]
   */
  final String children;

  /**
   * Compile the child nodes of the element.  This is the default.
   */
  static const String COMPILE_CHILDREN = 'compile';
  /**
   * Compile the child nodes for transclusion and makes available
   * [BoundBlockFactory], [BlockFactory] and [BlockHole] for injection.
   */
  static const String TRANSCLUDE_CHILDREN = 'transclude';
  /**
   * Do not compile/visit the child nodes.  Angular markup on descendant nodes
   * will not be processed.
   */
  static const String IGNORE_CHILDREN = 'ignore';

  /**
   * A directive/component controller class can be injected into other
   * directives/components. This attribute controls whether the
   * controller is available to others.
   *
   * * `local` [NgDirective.LOCAL_VISIBILITY] - the controller can be injected
   *   into other directives / components on the same DOM element.
   * * `children` [NgDirective.CHILDREN_VISIBILITY] - the controller can be
   *   injected into other directives / components on the same or child DOM
   *   elements.
   * * `direct_children` [NgDirective.DIRECT_CHILDREN_VISIBILITY] - the
   *   controller can be injected into other directives / components on the
   *   direct children of the current DOM element.
   */
  final String visibility;
  final List<Type> publishTypes;

  /**
   * Use map to define the mapping of component's DOM attributes into
   * the component instance or scope. The map's key is the DOM attribute name
   * to map in camelCase (DOM attribute is in dash-case). The Map's value
   * consists of a mode character, and an expression. If expression is not
   * specified, it maps to the same scope parameter as is the DOM attribute.
   *
   * * `@` - Map the DOM attribute string. The attribute string will be taken
   *   literally or interpolated if it contains binding {{}} systax.
   *
   * * `=` - Treat the DOM attribute value as an expression. Set up a watch
   *   on both outside as well as component scope to keep the src and
   *   destination in sync.
   *
   * * `!` - Treat the DOM attribute value as an expression. Set up a one time
   *   watch on expression. Once the expression turns truthy it will no longer
   *   update.
   *
   * * `&` - Treat the DOM attribute value as an expression. Assign a closure
   *   function into the component. This allows the component to control
   *   the invocation of the closure. This is useful for passing
   *   expressions into controllers which act like callbacks.
   *
   * NOTE: an expression may start with `.` which evaluates the expression
   * against the current controller rather then current scope.
   *
   * Example:
   *
   *     <my-component title="Hello {{username}}"
   *                   selection="selectedItem"
   *                   on-selection-change="doSomething()">
   *
   *     @NgComponent(
   *       selector: 'my-component'
   *       map: const {
   *         'title': '@.title',
   *         'selection': '=.currentItem',
   *         'onSelectionChange': '&.onChange'
   *       }
   *     )
   *     class MyComponent {
   *       String title;
   *       var currentItem;
   *       ParsedFn onChange;
   *     }
   *
   *  The above example shows how all three mapping modes are used.
   *
   *  * `@.title` maps the title DOM attribute to the controller `title`
   *    field. Notice that this maps the content of the attribute, which
   *    means that it can be used with `{{}}` interpolation.
   *
   *  * `=.currentItem` maps the expression (in this case the `selectedItem`
   *    in the current scope into the `currentItem` in the controller. Notice
   *    that mapping is bi-directional. A change either in controller or on
   *    parent scope will result in change of the other.
   *
   *  * `&.onChange` maps the expression into tho controllers `onChange`
   *    field. The result of mapping is a callable function which can be
   *    invoked at any time by the controller. The invocation of the
   *    callable function will result in the expression `doSomething()` to
   *    be executed in the parent context.
   */
  final Map<String, String> map;

  /**
   * Use the list to specify expression containing attributes which are not
   * included under [map] with '=' or '@' specification.
   */
  final List<String> exportExpressionAttrs;

  /**
   * Use the list to specify a expressions which are evaluated dynamically
   * (ex. via [Scope.$eval]) and are otherwise not statically discoverable.
   */
  final List<String> exportExpressions;

  /**
   * An expression under which the controller instance will be published into.
   * This allows the expressions in the template to be referring to controller
   * instance and its properties.
   */
  final String publishAs;

  const NgAnnotation({
    this.selector,
    this.children: NgAnnotation.COMPILE_CHILDREN,
    this.visibility: NgDirective.LOCAL_VISIBILITY,
    this.publishAs,
    this.publishTypes: const [],
    this.map: const {},
    this.exportExpressions: const [],
    this.exportExpressionAttrs: const []
  });

  toString() => selector;
  get hashCode => selector.hashCode;
  operator==(other) =>
      other is NgAnnotation && this.selector == other.selector;

}


/**
 * Meta-data marker placed on a class which should act as a controller for the
 * component. Angular components are a light-weight version of web-components.
 * Angular components use shadow-DOM for rendering their templates.
 *
 * Angular components are instantiated using dependency injection, and can
 * ask for any injectable object in their constructor. Components
 * can also ask for other components or directives declared on the DOM element.
 *
 * Components can declared these optional methods:
 *
 * * `attach()` - Called on first [Scope.$digest()].
 *
 * * `detach()` - Called on when owning scope is destroyed.
 *
 */
class NgComponent extends NgAnnotation {
  /**
   * Inlined HTML template for the component.
   */
  final String template;

  /**
   * A URL to HTML template. This will be loaded asynchronously and
   * cached for future component instances.
   */
  final String templateUrl;

  /**
   * A CSS URL to load into the shadow DOM.
   */
  final String cssUrl;

  /**
   * Set the shadow root applyAuthorStyles property. See shadow-DOM
   * documentation for further details.
   */
  final bool applyAuthorStyles;

  /**
   * Set the shadow root resetStyleInheritance property. See shadow-DOM
   * documentation for further details.
   */
  final bool resetStyleInheritance;

  const NgComponent({
    this.template,
    this.templateUrl,
    this.cssUrl,
    this.applyAuthorStyles,
    this.resetStyleInheritance,
    publishAs,
    map,
    selector,
    visibility,
    publishTypes : const <Type>[],
    exportExpressions,
    exportExpressionAttrs
  }) : super(selector: selector,
             children: NgAnnotation.COMPILE_CHILDREN,
             visibility: visibility,
             publishTypes: publishTypes,
             publishAs: publishAs,
             map: map,
             exportExpressions: exportExpressions,
             exportExpressionAttrs: exportExpressionAttrs);
}

RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$');

class NgDirective extends NgAnnotation {
  static const String LOCAL_VISIBILITY = 'local';
  static const String CHILDREN_VISIBILITY = 'children';
  static const String DIRECT_CHILDREN_VISIBILITY = 'direct_children';

  final String attrName;

  const NgDirective({
    children: NgAnnotation.COMPILE_CHILDREN,
    this.attrName: null,
    publishAs,
    map,
    selector,
    visibility,
    publishTypes : const <Type>[],
    exportExpressions,
    exportExpressionAttrs
  }) : super(selector: selector, children: children, visibility: visibility,
      publishTypes: publishTypes, publishAs: publishAs, map: map,
      exportExpressions: exportExpressions,
      exportExpressionAttrs: exportExpressionAttrs);

  get defaultAttributeName {
    if (attrName == null && selector != null) {
      var match = _ATTR_NAME.firstMatch(selector);
      return match != null ? match[1] : null;
    }
    return attrName;
  }
}

/**
 * Implementing directives or components [attach] method will be called when
 * the next scope digest occurs after component instantiation. It is guaranteed
 * that when [attach] is invoked, that all attribute mappings have already
 * been processed.
 */
abstract class NgAttachAware {
  void attach();
}

/**
 * Implementing directives or components [detach] method will be called when
 * the associated scope is destroyed.
 */
abstract class NgDetachAware {
  void detach();
}

class DirectiveMap extends AnnotationMap<NgAnnotation> {
  DirectiveMap(Injector injector, MetadataExtractor metadataExtractor)
      : super(injector, metadataExtractor);
}
library angular.tools.utils;

camelcase(String s) {
  var part = s.split('-').map((s) => s.toLowerCase());
  if (part.length <= 1) {
    return part.join();
  }
  return part.first + part.skip(1).map(capitalize).join();
}

capitalize(String s) => s.substring(0, 1).toUpperCase() + s.substring(1);

var SNAKE_CASE_REGEXP = new RegExp("[A-Z]");

snakecase(String name, [separator = '-']) =>
    name.replaceAllMapped(SNAKE_CASE_REGEXP, (Match match) =>
        (match.start != 0 ? separator : '') + match.group(0).toLowerCase());
library di.errors;


class NoProviderError extends ArgumentError {
  NoProviderError(message) : super(message);
}

class CircularDependencyError extends ArgumentError {
  CircularDependencyError(message) : super(message);
}
library perf_api;

import 'dart:async';

/**
 * A simple profiler api.
 */
class Profiler {
  
  /**
   * Const constructor allows instances of this class to be used as a no-op
   * implementation.
   */
  const Profiler();

  /**
   * Starts a new timer for a given action [name]. An [int] timer id will be
   * returned which can be used in [stopTimer] to stop the timer.
   *
   * [extraData] is additional information about the timed action. Implementing
   * profiler should not assume any semantic or syntactic structure of that
   * data and is free to ignore it in aggregate reports.
   */
  int startTimer(String name, [String extraData]) => null;

  /**
   * Stop a timer for a given [idOrName]. If [idOrName] is [int] then it's
   * treated as an action identifier returned from [startTimer]. If id is
   * invalid or timer for that id was already stopped then [ProfilerError]
   * will be thrown. If [idOrName] is [String] then the latest active timer
   * with that name will be stopped. If no active timer exists then
   * [ProfilerError] will be thrown.
   */
  void stopTimer(dynamic idOrName) {}

  /**
   * A simple zero-duration marker.
   */
  void markTime(String name, [String extraData]) {}

  /**
   * Times execution of the [functionOrFuture]. Body can either be a no argument
   * function or a [Future]. If function, it is executed synchronously and its
   * return value is returned. If it's a Future, then timing is stopped when the
   * future completes either successfully or with error.
   */
  dynamic time(String name, functionOrFuture, [String extraData]) {
    var id = startTimer(name, extraData);
    if (functionOrFuture is Function) {
      try {
        return functionOrFuture();
      } finally {
        stopTimer(id);
      }
    }
    if (functionOrFuture is Future) {
      return functionOrFuture.then(
          (v) {
            stopTimer(id);
            return v;
          },
          onError: (e) {
            stopTimer(id);
            throw e;
          });
    }
    throw new ProfilerError(
        'Invalid functionOrFuture or type ${functionOrFuture.runtimeType}');
  }
}

class ProfilerError extends Error {
  final String message;
  ProfilerError(String this.message);
  toString() => message;
}
library angular.core.parser;

import 'dart:mirrors';
import 'package:perf_api/perf_api.dart';

import '../../utils.dart';
import '../module.dart';


part 'backend.dart';
part 'lexer.dart';
part 'parser.dart';
part 'static_parser.dart';

// Placeholder for DI.
// The parser you are looking for is DynamicParser
abstract class Parser {
  call(String text) {}
  primaryFromToken(Token token, parserError);
}
part of angular.directive;

/**
 * The `ngClass` allows you to set CSS classes on HTML an element, dynamically,
 * by databinding an expression that represents all classes to be added.
 *
 * The directive won't add duplicate classes if a particular class was
 * already set.
 *
 * When the expression changes, the previously added classes are removed and
 * only then the new classes are added.
 *
 * The result of the expression evaluation can be a string representing space
 * delimited class names, an array, or a map of class names to boolean values.
 * In the case of a map, the names of the properties whose values are truthy
 * will be added as css classes to the element.
 *
 * ##Examples
 *
 * index.html:
 *
 *     <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
 *     <input type="checkbox" ng-model="bold"> bold
 *     <input type="checkbox" ng-model="strike"> strike
 *     <input type="checkbox" ng-model="red"> red
 *     <hr>
 *     <p ng-class="style">Using String Syntax</p>
 *     <input type="text" ng-model="style" placeholder="Type: bold strike red">
 *     <hr>
 *     <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
 *     <input ng-model="style1" placeholder="Type: bold"><br>
 *     <input ng-model="style2" placeholder="Type: strike"><br>
 *     <input ng-model="style3" placeholder="Type: red"><br>
 *
 * style.css:
 *
 *     .strike {
 *       text-decoration: line-through;
 *     }
 *     .bold {
 *         font-weight: bold;
 *     }
 *     .red {
 *         color: red;
 *     }
 *
 */
@NgDirective(
    selector: '[ng-class]',
    map: const {'ng-class': '@.valueExpression'})
class NgClassDirective extends _NgClassBase {
  NgClassDirective(dom.Element element, Scope scope, NodeAttrs attrs)
      : super(element, scope, null, attrs);
}

/**
 * The `ngClassOdd` and `ngClassEven` directives work exactly as
 * {@link ng.directive:ngClass ngClass}, except it works in
 * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
 *
 * This directive can be applied only within a scope of an `ngRepeat`.
 *
 * ##Examples
 *
 * index.html:
 *
 *     <li ng-repeat="name in ['John', 'Mary', 'Cate', 'Suz']">
 *       <span ng-class-odd="'odd'" ng-class-even="'even'">
 *         {{name}}
 *       </span>
 *     </li>
 *
 * style.css:
 *
 *     .odd {
 *       color: red;
 *     }
 *     .even {
 *       color: blue;
 *     }
 */
@NgDirective(
    selector: '[ng-class-odd]',
    map: const {'ng-class-odd': '@.valueExpression'})
class NgClassOddDirective extends _NgClassBase {
  NgClassOddDirective(dom.Element element, Scope scope, NodeAttrs attrs)
      : super(element, scope, 0, attrs);
}

/**
 * The `ngClassOdd` and `ngClassEven` directives work exactly as
 * {@link ng.directive:ngClass ngClass}, except it works in
 * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
 *
 * This directive can be applied only within a scope of an `ngRepeat`.
 *
 * ##Examples
 *
 * index.html:
 *
 *     <li ng-repeat="name in ['John', 'Mary', 'Cate', 'Suz']">
 *       <span ng-class-odd="'odd'" ng-class-even="'even'">
 *         {{name}}
 *       </span>
 *     </li>
 *
 * style.css:
 *
 *     .odd {
 *       color: red;
 *     }
 *     .even {
 *       color: blue;
 *     }
 */
@NgDirective(
    selector: '[ng-class-even]',
    map: const {'ng-class-even': '@.valueExpression'})
class NgClassEvenDirective extends _NgClassBase {
  NgClassEvenDirective(dom.Element element, Scope scope, NodeAttrs attrs)
      : super(element, scope, 1, attrs);
}

abstract class _NgClassBase {
  final dom.Element element;
  final Scope scope;
  final int mode;
  final NodeAttrs nodeAttrs;
  var previousSet = [];
  var currentSet = [];

  _NgClassBase(this.element, this.scope, this.mode, this.nodeAttrs) {
    var prevClass;

    nodeAttrs.observe('class', (String newValue) {
      if (prevClass != newValue) {
        prevClass = newValue;
        _handleChange(scope[r'$index']);
      }
    });
  }

  set valueExpression(currentExpression) {
    // this should be called only once, so we don't worry about cleaning up
    // watcher registrations.
    scope.$watchCollection(currentExpression, (current) {
      currentSet = _flatten(current);
      _handleChange(scope[r'$index']);
    });
    if (mode != null) {
      scope.$watch(r'$index', (index, oldIndex) {
        var mod = index % 2;
        if (oldIndex == null || mod != oldIndex % 2) {
          if (mod == mode) {
            element.classes.addAll(currentSet);
          } else {
            element.classes.removeAll(previousSet);
          }
        }
      });
    }
  }

  _handleChange(index) {
    if (mode == null || (index != null && index % 2 == mode)) {
      element.classes.removeAll(previousSet);
      element.classes.addAll(currentSet);
    }

    previousSet = currentSet;
  }

  static List<String> _flatten(classes) {
    if (classes == null) return [];
    if (classes is List) {
      return classes;
    }
    if (classes is Map) {
      return classes.keys.where((key) => toBool(classes[key])).toList();
    }
    if (classes is String) {
      return classes.split(' ');
    }
    throw 'ng-class expects expression value to be List, Map or String.';
  }
}
part of angular.core;

abstract class AnnotationMap<K> {
  final Map<K, Type> _map = {};

  AnnotationMap(Injector injector, MetadataExtractor extractMetadata) {
    injector.types.forEach((type) {
      var meta = extractMetadata(type)
        .where((annotation) => annotation is K)
        .forEach((annotation) {
          if (_map.containsKey(annotation)) {
            var annotationType = K;
            throw "Duplicate annotation found: $annotationType: $annotation. " +
                  "Exisitng: ${_map[annotation]}; New: $type.";
          }
          _map[annotation] = type;
        });
    });
  }

  Type operator[](K annotation) {
    var value = _map[annotation];
    if (value == null) {
      throw 'No $annotation found!';
    }
    return value;
  }

  forEach(fn(K, Type)) => _map.forEach(fn);
}

class MetadataExtractor {

  Iterable call(Type type) {
    var metadata = reflectClass(type).metadata;
    if (metadata == null) return [];
    return metadata.map((InstanceMirror im) => im.reflectee);
  }
}
part of angular.directive;

/**
 * The ngSwitch directive is used to conditionally swap DOM structure on your
 * template based on a scope expression. Elements within ngSwitch but without
 * ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
 * as specified in the template.
 *
 * The directive itself works similar to ngInclude, however, instead of
 * downloading template code (or loading it from the template cache), ngSwitch
 * simply choses one of the nested elements and makes it visible based on which
 * element matches the value obtained from the evaluated expression. In other
 * words, you define a container element (where you place the directive), place
 * an expression on the **ng-switch="..." attribute**, define any inner elements
 * inside of the directive and place a when attribute per element. The when
 * attribute is used to inform ngSwitch which element to display when the on
 * expression is evaluated. If a matching expression is not found via a when
 * attribute then an element with the default attribute is displayed.
 *
 * ## Example:
 *
 *     <ANY ng-switch="expression">
 *       <ANY ng-switch-when="matchValue1">...</ANY>
 *       <ANY ng-switch-when="matchValue2">...</ANY>
 *       <ANY ng-switch-default>...</ANY>
 *     </ANY>
 *
 * On child elements add:
 *
 * * `ngSwitchWhen`: the case statement to match against. If match then this
 *   case will be displayed. If the same match appears multiple times, all the
 *   elements will be displayed.
 * * `ngSwitchDefault`: the default case when no other case match. If there
 *   are multiple default cases, all of them will be displayed when no other
 *   case match.
 *
 * ## Example:
 *
 *     <div>
 *       <button ng-click="selection='settings'">Show Settings</button>
 *       <button ng-click="selection='home'">Show Home Span</button>
 *       <button ng-click="selection=''">Show default</button>
 *       <tt>selection={{selection}}</tt>
 *       <hr/>
 *       <div ng-switch="selection">
 *           <div ng-switch-when="settings">Settings Div</div>
 *           <div ng-switch-when="home">Home Span</div>
 *           <div ng-switch-default>default</div>
 *       </div>
 *     </div>
 */
@NgDirective(
    selector: '[ng-switch]',
    map: const {
      'ng-switch': '=.value',
      'change': '&.onChange'
    },
    visibility: NgDirective.DIRECT_CHILDREN_VISIBILITY
)
class NgSwitchDirective {
  Map<String, List<_Case>> cases = new Map<String, List<_Case>>();
  List<_BlockScopePair> currentBlocks = <_BlockScopePair>[];
  Function onChange;
  Scope scope;

  NgSwitchDirective(Scope this.scope) {
    cases['?'] = <_Case>[];
  }

  addCase(String value, BlockHole anchor, BoundBlockFactory blockFactory) {
    cases.putIfAbsent(value, () => <_Case>[]);
    cases[value].add(new _Case(anchor, blockFactory));
  }

  set value(val) {
    currentBlocks
      ..forEach((_BlockScopePair pair) {
        pair.block.remove();
        pair.scope.$destroy();
      })
      ..clear();

    val = '!$val';
    (cases.containsKey(val) ? cases[val] : cases['?'])
        .forEach((_Case caze) {
          Scope childScope = scope.$new();
          var block = caze.blockFactory(childScope)
            ..insertAfter(caze.anchor);
          currentBlocks.add(new _BlockScopePair(block, childScope));
        });
    if (onChange != null) {
      onChange();
    }
  }
}

class _BlockScopePair {
  final Block block;
  final Scope scope;

  _BlockScopePair(this.block, this.scope);
}

class _Case {
  final BlockHole anchor;
  final BoundBlockFactory blockFactory;

  _Case(this.anchor, this.blockFactory);
}

@NgDirective(
    selector: '[ng-switch-when]',
    children: NgAnnotation.TRANSCLUDE_CHILDREN,
    map: const {
      '.': '@.value'
    }
)
class NgSwitchWhenDirective {
  final NgSwitchDirective ngSwitch;
  final BlockHole hole;
  final BoundBlockFactory blockFactory;
  final Scope scope;

  NgSwitchWhenDirective(NgSwitchDirective this.ngSwitch,
      BlockHole this.hole, BoundBlockFactory this.blockFactory,
      Scope this.scope);

  set value(String value) =>
      ngSwitch.addCase('!$value', hole, blockFactory);
}


@NgDirective(
    children: NgAnnotation.TRANSCLUDE_CHILDREN,
    selector: '[ng-switch-default]'
)
class NgSwitchDefaultDirective {

  NgSwitchDefaultDirective(NgSwitchDirective ngSwitch, BlockHole hole,
                        BoundBlockFactory blockFactory, Scope scope) {
    ngSwitch.addCase('?', hole, blockFactory);
  }
}
// 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.

part of intl;

// TODO(efortuna): Customized pattern system -- suggested by i18n needs
// feedback on appropriateness.
/**
 * DateFormat is for formatting and parsing dates in a locale-sensitive
 * manner.
 * It allows the user to choose from a set of standard date time formats as well
 * as specify a customized pattern under certain locales. Date elements that
 * vary across locales include month name, week name, field order, etc.
 * We also allow the user to use any customized pattern to parse or format
 * date-time strings under certain locales. Date elements that vary across
 * locales include month name, weekname, field, order, etc.
 *
 * Formatting dates in the default "en_US" format does not require any
 * initialization. e.g.
 *       print(new DateFormat.yMMMd().format(new Date.now()));
 *
 * But for other locales, the formatting data for the locale must be
 * obtained. This can currently be done
 * in one of three ways, determined by which library you import. In all cases,
 * the "initializeDateFormatting" method must be called and will return a future
 * that is complete once the locale data is available. The result of the future
 * isn't important, but the data for that locale is available to the date
 * formatting and parsing once it completes.
 *
 * The easiest option is that the data may be available locally, imported in a
 * library that contains data for all the locales.
 *       import 'package:intl/date_symbol_data_local.dart';
 *       initializeDateFormatting("fr_FR", null).then((_) => runMyCode());
 *
 * If we are running outside of a browser, we may want to read the data
 * from files in the file system.
 *       import 'package:intl/date_symbol_data_file.dart';
 *       initializeDateFormatting("de_DE", null).then((_) => runMyCode());
 *
 * If we are running in a browser, we may want to read the data from the
 * server using the XmlHttpRequest mechanism.
 *       import 'package:intl/date_symbol_data_http_request.dart';
 *       initializeDateFormatting("pt_BR", null).then((_) => runMyCode());
 *
 * The code in example/basic/basic_example.dart shows a full example of
 * using this mechanism.
 *
 * Once we have the locale data, we need to specify the particular format.
 * This library uses the ICU/JDK date/time pattern specification both for
 * complete format specifications and also the abbreviated "skeleton" form
 * which can also adapt to different locales and is preferred where available.
 *
 * Skeletons: These can be specified either as the ICU constant name or as the
 * skeleton to which it resolves. The supported set of skeletons is as follows
 *      ICU Name                   Skeleton
 *      --------                   --------
 *      DAY                          d
 *      ABBR_WEEKDAY                 E
 *      WEEKDAY                      EEEE
 *      ABBR_STANDALONE_MONTH        LLL
 *      STANDALONE_MONTH             LLLL
 *      NUM_MONTH                    M
 *      NUM_MONTH_DAY                Md
 *      NUM_MONTH_WEEKDAY_DAY        MEd
 *      ABBR_MONTH                   MMM
 *      ABBR_MONTH_DAY               MMMd
 *      ABBR_MONTH_WEEKDAY_DAY       MMMEd
 *      MONTH                        MMMM
 *      MONTH_DAY                    MMMMd
 *      MONTH_WEEKDAY_DAY            MMMMEEEEd
 *      ABBR_QUARTER                 QQQ
 *      QUARTER                      QQQQ
 *      YEAR                         y
 *      YEAR_NUM_MONTH               yM
 *      YEAR_NUM_MONTH_DAY           yMd
 *      YEAR_NUM_MONTH_WEEKDAY_DAY   yMEd
 *      YEAR_ABBR_MONTH              yMMM
 *      YEAR_ABBR_MONTH_DAY          yMMMd
 *      YEAR_ABBR_MONTH_WEEKDAY_DAY  yMMMEd
 *      YEAR_MONTH                   yMMMM
 *      YEAR_MONTH_DAY               yMMMMd
 *      YEAR_MONTH_WEEKDAY_DAY       yMMMMEEEEd
 *      YEAR_ABBR_QUARTER            yQQQ
 *      YEAR_QUARTER                 yQQQQ
 *      HOUR24                       H
 *      HOUR24_MINUTE                Hm
 *      HOUR24_MINUTE_SECOND         Hms
 *      HOUR                         j
 *      HOUR_MINUTE                  jm
 *      HOUR_MINUTE_SECOND           jms
 *      HOUR_MINUTE_GENERIC_TZ       jmv
 *      HOUR_MINUTE_TZ               jmz
 *      HOUR_GENERIC_TZ              jv
 *      HOUR_TZ                      jz
 *      MINUTE                       m
 *      MINUTE_SECOND                ms
 *      SECOND                       s
 *
 * Examples Using the US Locale:
 *
 *      Pattern                           Result
 *      ----------------                  -------
 *      new DateFormat.yMd()             -> 7/10/1996
 *      new DateFormat("yMd")            -> 7/10/1996
 *      new DateFormat.yMMMMd("en_US")   -> July 10, 1996
 *      new DateFormat("Hm", "en_US")    -> 12:08 PM
 *      new DateFormat.yMd().add_Hm()    -> 7/10/1996 12:08 PM
 *
 * Explicit Pattern Syntax: Formats can also be specified with a pattern string.
 * The skeleton forms will resolve to explicit patterns of this form, but will
 * also adapt to different patterns in different locales.
 * The following characters are reserved:
 *
 *     Symbol   Meaning                Presentation        Example
 *     ------   -------                ------------        -------
 *     G        era designator         (Text)              AD
 *     y        year                   (Number)            1996
 *     M        month in year          (Text & Number)     July & 07
 *     L        standalone month       (Text & Number)     July & 07
 *     d        day in month           (Number)            10
 *     c        standalone day         (Number)            10
 *     h        hour in am/pm (1~12)   (Number)            12
 *     H        hour in day (0~23)     (Number)            0
 *     m        minute in hour         (Number)            30
 *     s        second in minute       (Number)            55
 *     S        fractional second      (Number)            978
 *     E        day of week            (Text)              Tuesday
 *     D        day in year            (Number)            189
 *     a        am/pm marker           (Text)              PM
 *     k        hour in day (1~24)     (Number)            24
 *     K        hour in am/pm (0~11)   (Number)            0
 *     z        time zone              (Text)              Pacific Standard Time
 *     Z        time zone (RFC 822)    (Number)            -0800
 *     v        time zone (generic)    (Text)              Pacific Time
 *     Q        quarter                (Text)              Q3
 *     '        escape for text        (Delimiter)         'Date='
 *     ''       single quote           (Literal)           'o''clock'
 *
 * The count of pattern letters determine the format.
 *
 * **Text**:
 * * 5 pattern letters--use narrow form for standalone. Otherwise does not apply
 * * 4 or more pattern letters--use full form,
 * * 3 pattern letters--use short or abbreviated form if one exists
 * * less than 3--use numeric form if one exists
 *
 * **Number**: the minimum number of digits. Shorter numbers are zero-padded to
 * this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled
 * specially; that is, if the count of 'y' is 2, the Year will be truncated to
 * 2 digits. (e.g., if "yyyy" produces "1997", "yy" produces "97".) Unlike other
 * fields, fractional seconds are padded on the right with zero.
 *
 * **(Text & Number)**: 3 or over, use text, otherwise use number.
 *
 * Any characters not in the pattern will be treated as quoted text. For
 * instance, characters like ':', '.', ' ', '#' and '@' will appear in the
 * resulting text even though they are not enclosed in single quotes. In our
 * current pattern usage, not all letters have meanings. But those unused
 * letters are strongly discouraged to be used as quoted text without quotes,
 * because we may use other letters as pattern characters in the future.
 *
 * Examples Using the US Locale:
 *
 *     Format Pattern                     Result
 *     --------------                     -------
 *     "yyyy.MM.dd G 'at' HH:mm:ss vvvv"  1996.07.10 AD at 15:08:56 Pacific Time
 *     "EEE, MMM d, ''yy"                 Wed, July 10, '96
 *     "h:mm a"                           12:08 PM
 *     "hh 'o''clock' a, zzzz"            12 o'clock PM, Pacific Daylight Time
 *     "K:mm a, vvv"                      0:00 PM, PT
 *     "yyyyy.MMMMM.dd GGG hh:mm aaa"     01996.July.10 AD 12:08 PM
 *
 * When parsing a date string using the abbreviated year pattern ("yy"),
 * DateFormat must interpret the abbreviated year relative to some
 * century. It does this by adjusting dates to be within 80 years before and 20
 * years after the time the parse function is called. For example, using a
 * pattern of "MM/dd/yy" and a DateParse instance created on Jan 1, 1997,
 * the string "01/11/12" would be interpreted as Jan 11, 2012 while the string
 * "05/04/64" would be interpreted as May 4, 1964. During parsing, only
 * strings consisting of exactly two digits, as defined by {@link
 * java.lang.Character#isDigit(char)}, will be parsed into the default
 * century. Any other numeric string, such as a one digit string, a three or
 * more digit string will be interpreted as its face value.
 *
 * If the year pattern does not have exactly two 'y' characters, the year is
 * interpreted literally, regardless of the number of digits. So using the
 * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
 */

class DateFormat {

  /**
   * Creates a new DateFormat, using the format specified by [newPattern]. For
   * forms that match one of our predefined skeletons, we look up the
   * corresponding pattern in [locale] (or in the default locale if none is
   * specified) and use the resulting full format string. This is the
   * preferred usage, but if [newPattern] does not match one of the skeletons,
   * then it is used as a format directly, but will not be adapted to suit
   * the locale.
   *
   * For example, in an en_US locale, specifying the skeleton
   *     new DateFormat('yMEd');
   * or the explicit
   *     new DateFormat('EEE, M/d/y');
   * would produce the same result, a date of the form
   *     Wed, 6/27/2012
   * The first version would produce a different format string if used in
   * another locale, but the second format would always be the same.
   *
   * If [locale] does not exist in our set of supported locales then an
   * [ArgumentError] is thrown.
   */
  DateFormat([String newPattern, String locale]) {
    // TODO(alanknight): It should be possible to specify multiple skeletons eg
    // date, time, timezone all separately. Adding many or named parameters to
    // the constructor seems awkward, especially with the possibility of
    // confusion with the locale. A "fluent" interface with cascading on an
    // instance might work better? A list of patterns is also possible.
    _locale = Intl.verifiedLocale(locale, localeExists);
    addPattern(newPattern);
  }

  /**
   * Return a string representing [date] formatted according to our locale
   * and internal format.
   */
  String format(DateTime date) {
    // TODO(efortuna): read optional TimeZone argument (or similar)?
    var result = new StringBuffer();
    _formatFields.forEach((field) => result.write(field.format(date)));
    return result.toString();
  }

  /**
   * Returns a date string indicating how long ago (3 hours, 2 minutes)
   * something has happened or how long in the future something will happen
   * given a [reference] DateTime relative to the current time.
   */
  String formatDuration(DateTime reference) {
    return '';
  }

  /**
   * Formats a string indicating how long ago (negative [duration]) or how far
   * in the future (positive [duration]) some time is with respect to a
   * reference [date].
   */
  String formatDurationFrom(Duration duration, DateTime date) {
    return '';
  }

  /**
   * Given user input, attempt to parse the [inputString] into the anticipated
   * format, treating it as being in the local timezone. If [inputString] does
   * not match our format, throws a [FormatException].
   */
  DateTime parse(String inputString, [utc = false]) {
    // TODO(alanknight): The Closure code refers to special parsing of numeric
    // values with no delimiters, which we currently don't do. Should we?
    var dateFields = new _DateBuilder();
    if (utc) dateFields.utc=true;
    var stream = new _Stream(inputString);
    _formatFields.forEach(
        (each) => each.parse(stream, dateFields));
    return dateFields.asDate();
  }

  /**
   * Given user input, attempt to parse the [inputString] into the anticipated
   * format, treating it as being in UTC.
   */
  DateTime parseUTC(String inputString) {
    return parse(inputString, true);
  }

  /**
   * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
   */
  String get locale => _locale;

  /**
   * Returns a list of all locales for which we have date formatting
   * information.
   */
  static List<String> allLocalesWithSymbols() => dateTimeSymbols.keys.toList();

  /**
   * The named constructors for this class are all conveniences for creating
   * instances using one of the known "skeleton" formats, and having code
   * completion support for discovering those formats.
   * So,
   *     new DateFormat.yMd("en_US")
   * is equivalent to
   *     new DateFormat("yMd", "en_US")
   * To create a compound format you can use these constructors in combination
   * with the add_ methods below. e.g.
   *     new DateFormat.yMd().add_Hms();
   * If the optional [locale] is omitted, the format will be created using the
   * default locale in [Intl.systemLocale].
   */
  DateFormat.d([locale]) : this("d", locale);
  DateFormat.E([locale]) : this("E", locale);
  DateFormat.EEEE([locale]) : this("EEEE", locale);
  DateFormat.LLL([locale]) : this("LLL", locale);
  DateFormat.LLLL([locale]) : this("LLLL", locale);
  DateFormat.M([locale]) : this("M", locale);
  DateFormat.Md([locale]) : this("Md", locale);
  DateFormat.MEd([locale]) : this("MEd", locale);
  DateFormat.MMM([locale]) : this("MMM", locale);
  DateFormat.MMMd([locale]) : this("MMMd", locale);
  DateFormat.MMMEd([locale]) : this("MMMEd", locale);
  DateFormat.MMMM([locale]) : this("MMMM", locale);
  DateFormat.MMMMd([locale]) : this("MMMMd", locale);
  DateFormat.MMMMEEEEd([locale]) : this("MMMMEEEEd", locale);
  DateFormat.QQQ([locale]) : this("QQQ", locale);
  DateFormat.QQQQ([locale]) : this("QQQQ", locale);
  DateFormat.y([locale]) : this("y", locale);
  DateFormat.yM([locale]) : this("yM", locale);
  DateFormat.yMd([locale]) : this("yMd", locale);
  DateFormat.yMEd([locale]) : this("yMEd", locale);
  DateFormat.yMMM([locale]) : this("yMMM", locale);
  DateFormat.yMMMd([locale]) : this("yMMMd", locale);
  DateFormat.yMMMEd([locale]) : this("yMMMEd", locale);
  DateFormat.yMMMM([locale]) : this("yMMMM", locale);
  DateFormat.yMMMMd([locale]) : this("yMMMMd", locale);
  DateFormat.yMMMMEEEEd([locale]) : this("yMMMMEEEEd", locale);
  DateFormat.yQQQ([locale]) : this("yQQQ", locale);
  DateFormat.yQQQQ([locale]) : this("yQQQQ", locale);
  DateFormat.H([locale]) : this("H", locale);
  DateFormat.Hm([locale]) : this("Hm", locale);
  DateFormat.Hms([locale]) : this("Hms", locale);
  DateFormat.j([locale]) : this("j", locale);
  DateFormat.jm([locale]) : this("jm", locale);
  DateFormat.jms([locale]) : this("jms", locale);
  DateFormat.jmv([locale]) : this("jmv", locale);
  DateFormat.jmz([locale]) : this("jmz", locale);
  DateFormat.jv([locale]) : this("jv", locale);
  DateFormat.jz([locale]) : this("jz", locale);
  DateFormat.m([locale]) : this("m", locale);
  DateFormat.ms([locale]) : this("ms", locale);
  DateFormat.s([locale]) : this("s", locale);

  /**
   * The "add_*" methods append a particular skeleton to the format, or set
   * it as the only format if none was previously set. These are primarily
   * useful for creating compound formats. For example
   *       new DateFormat.yMd().add_Hms();
   * would create a date format that prints both the date and the time.
   */
  DateFormat add_d() => addPattern("d");
  DateFormat add_E() => addPattern("E");
  DateFormat add_EEEE() => addPattern("EEEE");
  DateFormat add_LLL() => addPattern("LLL");
  DateFormat add_LLLL() => addPattern("LLLL");
  DateFormat add_M() => addPattern("M");
  DateFormat add_Md() => addPattern("Md");
  DateFormat add_MEd() => addPattern("MEd");
  DateFormat add_MMM() => addPattern("MMM");
  DateFormat add_MMMd() => addPattern("MMMd");
  DateFormat add_MMMEd() => addPattern("MMMEd");
  DateFormat add_MMMM() => addPattern("MMMM");
  DateFormat add_MMMMd() => addPattern("MMMMd");
  DateFormat add_MMMMEEEEd() => addPattern("MMMMEEEEd");
  DateFormat add_QQQ() => addPattern("QQQ");
  DateFormat add_QQQQ() => addPattern("QQQQ");
  DateFormat add_y() => addPattern("y");
  DateFormat add_yM() => addPattern("yM");
  DateFormat add_yMd() => addPattern("yMd");
  DateFormat add_yMEd() => addPattern("yMEd");
  DateFormat add_yMMM() => addPattern("yMMM");
  DateFormat add_yMMMd() => addPattern("yMMMd");
  DateFormat add_yMMMEd() => addPattern("yMMMEd");
  DateFormat add_yMMMM() => addPattern("yMMMM");
  DateFormat add_yMMMMd() => addPattern("yMMMMd");
  DateFormat add_yMMMMEEEEd() => addPattern("yMMMMEEEEd");
  DateFormat add_yQQQ() => addPattern("yQQQ");
  DateFormat add_yQQQQ() => addPattern("yQQQQ");
  DateFormat add_H() => addPattern("H");
  DateFormat add_Hm() => addPattern("Hm");
  DateFormat add_Hms() => addPattern("Hms");
  DateFormat add_j() => addPattern("j");
  DateFormat add_jm() => addPattern("jm");
  DateFormat add_jms() => addPattern("jms");
  DateFormat add_jmv() => addPattern("jmv");
  DateFormat add_jmz() => addPattern("jmz");
  DateFormat add_jv() => addPattern("jv");
  DateFormat add_jz() => addPattern("jz");
  DateFormat add_m() => addPattern("m");
  DateFormat add_ms() => addPattern("ms");
  DateFormat add_s() => addPattern("s");

  /**
   * For each of the skeleton formats we also allow the use of the corresponding
   * ICU constant names.
   */
  static const String ABBR_MONTH = 'MMM';
  static const String DAY = 'd';
  static const String ABBR_WEEKDAY = 'E';
  static const String WEEKDAY = 'EEEE';
  static const String ABBR_STANDALONE_MONTH = 'LLL';
  static const String STANDALONE_MONTH = 'LLLL';
  static const String NUM_MONTH = 'M';
  static const String NUM_MONTH_DAY = 'Md';
  static const String NUM_MONTH_WEEKDAY_DAY = 'MEd';
  static const String ABBR_MONTH_DAY = 'MMMd';
  static const String ABBR_MONTH_WEEKDAY_DAY = 'MMMEd';
  static const String MONTH = 'MMMM';
  static const String MONTH_DAY = 'MMMMd';
  static const String MONTH_WEEKDAY_DAY = 'MMMMEEEEd';
  static const String ABBR_QUARTER = 'QQQ';
  static const String QUARTER = 'QQQQ';
  static const String YEAR = 'y';
  static const String YEAR_NUM_MONTH = 'yM';
  static const String YEAR_NUM_MONTH_DAY = 'yMd';
  static const String YEAR_NUM_MONTH_WEEKDAY_DAY = 'yMEd';
  static const String YEAR_ABBR_MONTH = 'yMMM';
  static const String YEAR_ABBR_MONTH_DAY = 'yMMMd';
  static const String YEAR_ABBR_MONTH_WEEKDAY_DAY = 'yMMMEd';
  static const String YEAR_MONTH = 'yMMMM';
  static const String YEAR_MONTH_DAY = 'yMMMMd';
  static const String YEAR_MONTH_WEEKDAY_DAY = 'yMMMMEEEEd';
  static const String YEAR_ABBR_QUARTER = 'yQQQ';
  static const String YEAR_QUARTER = 'yQQQQ';
  static const String HOUR24 = 'H';
  static const String HOUR24_MINUTE = 'Hm';
  static const String HOUR24_MINUTE_SECOND = 'Hms';
  static const String HOUR = 'j';
  static const String HOUR_MINUTE = 'jm';
  static const String HOUR_MINUTE_SECOND = 'jms';
  static const String HOUR_MINUTE_GENERIC_TZ = 'jmv';
  static const String HOUR_MINUTE_TZ = 'jmz';
  static const String HOUR_GENERIC_TZ = 'jv';
  static const String HOUR_TZ = 'jz';
  static const String MINUTE = 'm';
  static const String MINUTE_SECOND = 'ms';
  static const String SECOND = 's';

  /** The locale in which we operate, e.g. 'en_US', or 'pt'. */
  String _locale;

  /**
   * The full template string. This may have been specified directly, or
   * it may have been derived from a skeleton and the locale information
   * on how to interpret that skeleton.
   */
  String _pattern;

  /**
   * We parse the format string into individual [_DateFormatField] objects
   * that are used to do the actual formatting and parsing. Do not use
   * this variable directly, use the getter [_formatFields].
   */
  List<_DateFormatField> _formatFieldsPrivate;

  /**
   * Getter for [_formatFieldsPrivate] that lazily initializes it.
   */
  get _formatFields {
    if (_formatFieldsPrivate == null) {
      if (_pattern == null) _useDefaultPattern();
      _formatFieldsPrivate = parsePattern(_pattern);
    }
    return _formatFieldsPrivate;
  }

  /**
   * We are being asked to do formatting without having set any pattern.
   * Use a default.
   */
  _useDefaultPattern() {
    add_yMMMMd();
    add_jms();
  }

  /**
   * A series of regular expressions used to parse a format string into its
   * component fields.
   */
  static List<RegExp> _matchers = [
      // Quoted String - anything between single quotes, with escaping
      //   of single quotes by doubling them.
      // e.g. in the pattern "hh 'o''clock'" will match 'o''clock'
      new RegExp("^\'(?:[^\']|\'\')*\'"),
      // Fields - any sequence of 1 or more of the same field characters.
      // e.g. in "hh:mm:ss" will match hh, mm, and ss. But in "hms" would
      // match each letter individually.
      new RegExp(
        "^(?:G+|y+|M+|k+|S+|E+|a+|h+|K+|H+|c+|L+|Q+|d+|D+|m+|s+|v+|z+|Z+)"),
      // Everything else - A sequence that is not quotes or field characters.
      // e.g. in "hh:mm:ss" will match the colons.
      new RegExp("^[^\'GyMkSEahKHcLQdDmsvzZ]+")
  ];

  /**
   * Set our pattern, appending it to any existing patterns. Also adds a single
   * space to separate the two.
   */
  _appendPattern(String inputPattern, [String separator = ' ']) {
    if (_pattern == null) {
      _pattern = inputPattern;
    } else {
      _pattern = "$_pattern$separator$inputPattern";
    }
  }

  /**
   * Add [inputPattern] to this instance as a pattern. If there was a previous
   * pattern, then this appends to it, separating the two by [separator].
   * [inputPattern] is first looked up in our list of known skeletons.
   * If it's found there, then use the corresponding pattern for this locale.
   * If it's not, then treat [inputPattern] as an explicit pattern.
   */
  DateFormat addPattern(String inputPattern, [String separator = ' ']) {
    // TODO(alanknight): This is an expensive operation. Caching recently used
    // formats, or possibly introducing an entire "locale" object that would
    // cache patterns for that locale could be a good optimization.
    // If we have already parsed the format fields, reset them.
    _formatFieldsPrivate = null;
    if (inputPattern == null) return this;
    if (!_availableSkeletons.containsKey(inputPattern)) {
      _appendPattern(inputPattern, separator);
    } else {
      _appendPattern(_availableSkeletons[inputPattern], separator);
    }
    return this;
  }

  /** Return the pattern that we use to format dates.*/
  get pattern => _pattern;

  /** Return the skeletons for our current locale. */
  Map get _availableSkeletons {
    return dateTimePatterns[locale];
  }

  /**
   * Return the [DateSymbol] information for the locale. This can be useful
   * to find lists like the names of weekdays or months in a locale, but
   * the structure of this data may change, and it's generally better to go
   * through the [format] and [parse] APIs. If the locale isn't present, or
   * is uninitialized, returns null;
   */
  DateSymbols get dateSymbols => dateTimeSymbols[_locale];

  /**
   * Set the locale. If the locale can't be found, we also look up
   * based on alternative versions, e.g. if we have no 'en_CA' we will
   * look for 'en' as a fallback. It will also translate en-ca into en_CA.
   * Null is also considered a valid value for [newLocale], indicating
   * to use the default.
   */
  _setLocale(String newLocale) {
    _locale = Intl.verifiedLocale(newLocale, localeExists);
  }

  /**
   * Return true if the locale exists, or if it is null. The null case
   * is interpreted to mean that we use the default locale.
   */
  static bool localeExists(localeName) {
    if (localeName == null) return false;
    return dateTimeSymbols.containsKey(localeName);
  }

  static List get _fieldConstructors => [
      (pattern, parent) => new _DateFormatQuotedField(pattern, parent),
      (pattern, parent) => new _DateFormatPatternField(pattern, parent),
      (pattern, parent) => new _DateFormatLiteralField(pattern, parent)];

  /** Parse the template pattern and return a list of field objects.*/
  List parsePattern(String pattern) {
    if (pattern == null) return null;
    return _parsePatternHelper(pattern).reversed.toList();
  }

  /** Recursive helper for parsing the template pattern. */
  List _parsePatternHelper(String pattern) {
    if (pattern.isEmpty) return [];

    var matched = _match(pattern);
    if (matched == null) return [];

    var parsed = _parsePatternHelper(
                      pattern.substring(matched.fullPattern().length));
    parsed.add(matched);
    return parsed;
  }

  /** Find elements in a string that are patterns for specific fields.*/
  _DateFormatField _match(String pattern) {
    for (var i = 0; i < _matchers.length; i++) {
      var regex = _matchers[i];
      var match = regex.firstMatch(pattern);
      if (match != null) {
        return _fieldConstructors[i](match.group(0), this);
      }
    }
  }
}
// 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.

/**
 * A library for general helper code associated with the intl library
 * rather than confined to specific parts of it.
 */

library intl_helpers;

import 'dart:async';

/**
 * This is used as a marker for a locale data map that hasn't been initialized,
 * and will throw an exception on any usage that isn't the fallback
 * patterns/symbols provided.
 */
class UninitializedLocaleData<F> {
  final String message;
  final F fallbackData;
  const UninitializedLocaleData(this.message, this.fallbackData);

  operator [](String key) =>
      (key == 'en_US') ? fallbackData : _throwException();

  String lookupMessage(String message_str, [final String desc='',
      final Map examples=const {}, String locale,
      String name, List<String> args]) => message_str;

  List get keys => _throwException();

  bool containsKey(String key) => (key == 'en_US') ? true : _throwException();

  _throwException() {
    throw new LocaleDataException("Locale data has not been initialized"
        ", call $message.");
  }
}

class LocaleDataException implements Exception {
  final String message;
  LocaleDataException(this.message);
  toString() => "LocaleDataException: $message";
}

/**
 *  An abstract superclass for data readers to keep the type system happy.
 */
abstract class LocaleDataReader {
  Future read(String locale);
}

/**
 * The internal mechanism for looking up messages. We expect this to be set
 * by the implementing package so that we're not dependent on its
 * implementation.
 */
var messageLookup = const
    UninitializedLocaleData('initializeMessages(<locale>)', null);

/**
 * Initialize the message lookup mechanism. This is for internal use only.
 * User applications should import `message_lookup_by_library.dart` and call
 * `initializeMessages`
 */
void initializeInternalMessageLookup(Function lookupFunction) {
  if (messageLookup is UninitializedLocaleData) {
    messageLookup = lookupFunction();
  }
}
import 'package:angular/angular.dart';

@NgDirective(selector: '[toy-data]')
class ToyData {
  ToyData(Scope scope) {
    scope.friends = [{'name':'John',     'phone':'555-1276'},
                     {'name':'Mary',     'phone':'800-BIG-MARY'},
                     {'name':'Mike',     'phone':'555-4321'},
                     {'name':'Adam',     'phone':'555-5678'},
                     {'name':'Julie',    'phone':'555-8765'},
                     {'name':'Juliette', 'phone':'555-5678'}];
  }
}

main() {
  bootstrapAngular([new AngularModule()..type(ToyData)], 'html');
}
part of angular.filter;

/**
 * Creates a new List or String containing only a prefix/suffix of the
 * elements as specified by the `limit` parameter.
 *
 * When operating on a List, the returned list is always a copy even when all
 * the elements are being returned.
 *
 * When the `limit` expression evaluates to a positive integer, `limit` items
 * from the beginning of the List/String are returned.  When `limit` evaluates
 * to a negative integer, `|limit|` items from the end of the List/String are
 * returned.  If `|limit|` is larger than the size of the List/String, then the
 * entire List/String is returned.  In the case of a List, a copy of the list is
 * returned.
 *
 * If the `limit` expression evaluates to a null or non-integer, then an empty
 * list is returned.  If the input is a null List/String, a null is returned.
 *
 * Example:
 *
 * - `{{ 'abcdefghij' | limitTo: 4 }}` → `'abcd'`
 * - `{{ 'abcdefghij' | limitTo: -4 }}` → `'ghij'`
 * - `{{ 'abcdefghij' | limitTo: -100 }}` → `'abcdefghij'`
 *
 * <br>
 *
 * This [ng-repeat] directive:
 *
 *     <li ng-repeat="i in 'abcdefghij' | limitTo:-2">{{i}}</li>
 *
 * results in
 *
 *     <li>i</li>
 *     <li>j</li>
 */
@NgFilter(name:'limitTo')
class LimitToFilter {
  Injector _injector;
  Parser _parser;

  LimitToFilter(Injector this._injector, Parser this._parser);

  dynamic call(dynamic items, [int limit]) {
    if (items == null) {
      return null;
    }
    if (limit == null) {
      return const[];
    }
    if (items is! List && items is! String) {
      return items;
    }
    int i = 0, j = items.length;
    if (limit > -1) {
      j = (limit > j) ? j : limit;
    } else {
      i = j + limit;
      if (i < 0) {
        i = 0;
      }
    }
    if (items is String) {
      return (items as String).substring(i, j);
    } else {
      return (items as List).getRange(i, j).toList(growable: false);
    }
  }
}
library angular.util;

toBool(x) {
  if (x is bool) return x;
  if (x is int || x is double) return x != 0;
  return false;
}

typedef FnWith0Args();
typedef FnWith1Args(a0);
typedef FnWith2Args(a0, a1);
typedef FnWith3Args(a0, a1, a2);
typedef FnWith4Args(a0, a1, a2, a3);
typedef FnWith5Args(a0, a1, a2, a3, a4);

relaxFnApply(Function fn, List args) {
// Check the args.length to support functions with optional parameters.
  var argsLen = args.length;
  if (fn is Function && fn != null) {
    if (fn is FnWith5Args && argsLen > 4) {
      return fn(args[0], args[1], args[2], args[3], args[4]);
    } else if (fn is FnWith4Args && argsLen > 3) {
      return fn(args[0], args[1], args[2], args[3]);
    } else if (fn is FnWith3Args && argsLen > 2 ) {
      return fn(args[0], args[1], args[2]);
    } else if (fn is FnWith2Args && argsLen > 1 ) {
      return fn(args[0], args[1]);
    } else if (fn is FnWith1Args && argsLen > 0) {
      return fn(args[0]);
    } else if (fn is FnWith0Args) {
      return fn();
    } else {
      throw "Unknown function type, expecting 0 to 5 args.";
    }
  } else {
    throw "Missing function.";
  }
}

relaxFnArgs1(Function fn) {
  if (fn is FnWith3Args) return (_1) => fn(_1, null, null);
  if (fn is FnWith2Args) return (_1) => fn(_1, null);
  if (fn is FnWith1Args) return fn;
  if (fn is FnWith0Args) return (_1) => fn();
}

relaxFnArgs3(Function fn) {
  if (fn is FnWith3Args) return fn;
  if (fn is FnWith2Args) return (_1, _2, _3) => fn(_1, null);
  if (fn is FnWith1Args) return (_1, _2, _3) => fn(_1);
  if (fn is FnWith0Args) return (_1, _2, _3) => fn();
}

relaxFnArgs(Function fn) {
  if (fn is FnWith5Args) {
    return ([a0, a1, a2, a3, a4]) => fn(a0, a1, a2, a3, a4);
  } else if (fn is FnWith4Args) {
    return ([a0, a1, a2, a3, a4]) => fn(a0, a1, a2, a3);
  } else if (fn is FnWith3Args) {
    return ([a0, a1, a2, a3, a4]) => fn(a0, a1, a2);
  } else if (fn is FnWith2Args) {
    return ([a0, a1, a2, a3, a4]) => fn(a0, a1);
  } else if (fn is FnWith1Args) {
    return ([a0, a1, a2, a3, a4]) => fn(a0);
  } else if (fn is FnWith0Args) {
    return ([a0, a1, a2, a3, a4]) => fn();
  } else {
    return ([a0, a1, a2, a3, a4]) {
      throw "Unknown function type, expecting 0 to 5 args.";
    };
  }
}
part of angular.core.dom;

@NgDirective(selector: r':contains(/{{.*}}/)')
class NgTextMustacheDirective {
  dom.Node element;
  Expression interpolateFn;

  // This Directive is special and does not go through injection.
  NgTextMustacheDirective(dom.Node this.element,
                          String markup,
                          Interpolate interpolate,
                          Scope scope,
                          TextChangeListener listener) {
    interpolateFn = interpolate(markup);
    setter(text) {
      element.text = text;
      if (listener != null) listener.call(text);
    }
    setter('');
    scope.$watch(interpolateFn.eval, setter);
  }

}

@NgDirective(selector: r'[*=/{{.*}}/]')
class NgAttrMustacheDirective {
  static RegExp ATTR_NAME_VALUE_REGEXP = new RegExp(r'^([^=]+)=(.*)$');

// This Directive is special and does not go through injection.
  NgAttrMustacheDirective(NodeAttrs attrs, String markup, Interpolate interpolate, Scope scope) {
    var match = ATTR_NAME_VALUE_REGEXP.firstMatch(markup);
    var attrName = match[1];
    Expression interpolateFn = interpolate(match[2]);
    Function attrSetter = (text) => attrs[attrName] = text;
    attrSetter('');
    scope.$watch(interpolateFn.eval, attrSetter);
  }
}

part of angular.core;

/**
 * Use @[NgFilter] annotation to register a new filter. A filter is a class
 * with a [call] method (a callable function).
 *
 * Usage:
 *
 *     // Declaration
 *     @NgFilter(name:'myFilter')
 *     class MyFilter {
 *       call(valueToFilter, optArg1, optArg2) {
 *          return ...;
 *       }
 *     }
 *
 *
 *     // Registration
 *     var module = ...;
 *     module.type(MyFilter);
 *
 *
 *     <!-- Usage -->
 *     <span>{{something | myFilter:arg1:arg2}}</span>
 */
class NgFilter {
  final String name;

  const NgFilter({String this.name});

  int get hashCode => name.hashCode;
  bool operator==(other) => this.name == other.name;

  toString() => 'NgFilter: $name';
}

/**
 * Registry of filters at runtime.
 */
class FilterMap extends AnnotationMap<NgFilter> {
  Injector _injector;
  FilterMap(Injector injector, MetadataExtractor extractMetadata) : super(injector, extractMetadata) {
    this._injector = injector;
  }

  call(String name) {
    var filter = new NgFilter(name:name);
    var filterType = this[filter];
    return _injector.get(filterType);
  }
}

library angular.source_metadata_extractor ;

import 'package:analyzer_experimental/src/generated/ast.dart';

import 'source_crawler.dart';
import 'utils.dart';
import 'common.dart';

const String _COMPONENT = '-component';
const String _DIRECTIVE = '-directive';
String _ATTR_DIRECTIVE = '-attr' + _DIRECTIVE;
RegExp _ATTR_SELECTOR_REGEXP = new RegExp(r'\[([^\]]+)\]');

class SourceMetadataExtractor {
  SourceCrawler sourceCrawler;
  DirectiveMetadataCollectingVisitor metadataVisitor;

  SourceMetadataExtractor(this.sourceCrawler,
      [DirectiveMetadataCollectingVisitor this.metadataVisitor]) {
    if (metadataVisitor == null) {
      metadataVisitor = new DirectiveMetadataCollectingVisitor();
    }
  }

  List<DirectiveInfo> gatherDirectiveInfo(root) {
    sourceCrawler.crawl(root, metadataVisitor);

    List<DirectiveInfo> directives = <DirectiveInfo>[];
    metadataVisitor.metadata.forEach((DirectiveMetadata meta) {
      DirectiveInfo dirInfo = new DirectiveInfo();
      dirInfo.selector = meta.selector;
      meta.attributeMappings.forEach((attrName, mappingSpec) {
        if (mappingSpec.startsWith('=') ||
            mappingSpec.startsWith('&') ||
            mappingSpec.startsWith('@') ||
            mappingSpec.startsWith('!')) {
          dirInfo.expressionAttrs.add(snakecase(attrName));
        }
        if (mappingSpec.length == 1) { // shorthand
          // TODO(pavelgj): Figure out if short-hand LHS should be expanded
          // and added to the expressions list.
          if (attrName != '.') {
            dirInfo.expressions.add(attrName);
          }
        } else {
          mappingSpec = mappingSpec.substring(1);
          if (mappingSpec.startsWith('.')) {
            mappingSpec = mappingSpec.substring(1);
          }
          dirInfo.expressions.add(mappingSpec);
        }
      });

      meta.exportExpressionAttrs.forEach((attr) {
        attr = snakecase(attr);
        if (!dirInfo.expressionAttrs.contains(attr)) {
          dirInfo.expressionAttrs.add(attr);
        }
      });

      meta.exportExpressions.forEach((expr) {
        if (!dirInfo.expressions.contains(expr)) {
          dirInfo.expressions.add(expr);
        }
      });


      // No explicit selector specified on the directive, compute one.
      var className = snakecase(meta.className);
      if (dirInfo.selector == null) {
        if (meta.type == COMPONENT) {
          if (className.endsWith(_COMPONENT)) {
            dirInfo.selector = className.
                substring(0, className.length - _COMPONENT.length);
          } else {
            throw "Directive name '$className' must end with $_DIRECTIVE, "
            "$_ATTR_DIRECTIVE, $_COMPONENT or have a \$selector field.";
          }
        } else {
          if (className.endsWith(_ATTR_DIRECTIVE)) {
            var attrName = className.
                substring(0, className.length - _ATTR_DIRECTIVE.length);
            dirInfo.selector = '[$attrName]';
          } else if (className.endsWith(_DIRECTIVE)) {
            dirInfo.selector = className.
                substring(0, className.length - _DIRECTIVE.length);
          } else {
            throw "Directive name '$className' must end with $_DIRECTIVE, "
            "$_ATTR_DIRECTIVE, $_COMPONENT or have a \$selector field.";
          }
        }
      }
      var reprocessedAttrs = <String>[];
      dirInfo.expressionAttrs.forEach((String attr) {
        if (attr == '.') {
          var matches = _ATTR_SELECTOR_REGEXP.allMatches(dirInfo.selector);
          if (matches.length > 0) {
            reprocessedAttrs.add(matches.last.group(1));
          }
        } else {
          reprocessedAttrs.add(attr);
        }
      });
      dirInfo.expressionAttrs = reprocessedAttrs;
      directives.add(dirInfo);

    });

    return directives;
  }
}

class DirectiveMetadataCollectingVisitor {
  List<DirectiveMetadata> metadata = <DirectiveMetadata>[];

  call(CompilationUnit cu) {
    cu.declarations.forEach((CompilationUnitMember declaration) {
      // We only care about classes.
      if (declaration is! ClassDeclaration) return;
      ClassDeclaration clazz = declaration;
      clazz.metadata.forEach((Annotation ann) {
        if (ann.arguments == null) return; // Ignore non-class annotations.
        // TODO(pavelj): this is not a safe check for the type of the
        // annotations, but good enough for now.
        if (ann.name.name != 'NgComponent'
            && ann.name.name != 'NgDirective') return;

        bool isComponent = ann.name.name == 'NgComponent';

        DirectiveMetadata meta = new DirectiveMetadata()
          ..className = clazz.name.name
          ..type = isComponent ? COMPONENT : DIRECTIVE;
        metadata.add(meta);

        ann.arguments.arguments.forEach((Expression arg) {
          if (arg is NamedExpression) {
            NamedExpression namedArg = arg;
            var paramName = namedArg.name.label.name;
            if (paramName == 'selector') {
              meta.selector = assertString(namedArg.expression).stringValue;
            }
            if (paramName == 'map') {
              MapLiteral map = namedArg.expression;
              map.entries.forEach((MapLiteralEntry entry) {
                meta.attributeMappings[assertString(entry.key).stringValue] =
                    assertString(entry.value).stringValue;
              });
            }
            if (paramName == 'exportExpressions') {
              meta.exportExpressions = getStringValues(namedArg.expression);
            }
            if (paramName == 'exportExpressionAttrs') {
              meta.exportExpressionAttrs = getStringValues(namedArg.expression);
            }
          }
        });
      });
    });
  }
}

List<String> getStringValues(ListLiteral listLiteral) {
  List<String> res = <String>[];
  for (Expression element in listLiteral.elements) {
    res.add(assertString(element).stringValue);
  }
  return res;
}

StringLiteral assertString(Expression key) {
  if (key is! StringLiteral) throw 'must be a string literal: ${key.runtimeType}';
  return key;
}
part of angular.core;


/**
 * Used by [Scope.$on] to notify the listeners of events.
 */
class ScopeEvent {
  String name;
  Scope targetScope;
  Scope currentScope;
  bool propagationStopped = false;
  bool defaultPrevented = false;

  ScopeEvent(this.name, this.targetScope);

  stopPropagation () => propagationStopped = true;
  preventDefault() => defaultPrevented = true;
}

/**
 * Allows the configuration of [Scope.$digest] iteration maximum time-to-live
 * value. Digest keeps checking the state of the watcher getters until it
 * can execute one full iteration with no watchers triggering. TTL is used
 * to prevent an infinite loop where watch A triggers watch B which in turn
 * triggers watch A. If the system does not stabilize in TTL iteration then
 * an digest is stop an an exception is thrown.
 */
class ScopeDigestTTL {
  final num ttl;
  ScopeDigestTTL(): ttl = 5;
  ScopeDigestTTL.value(num this.ttl);
}

/**
 * Scope has two responsibilities. 1) to keep track af watches and 2)
 * to keep references to the model so that they are available for
 * data-binding.
 */
@proxy
class Scope implements Map {
  String $id;
  Scope $parent;
  Scope $root;
  num _nextId = 0;

  ExceptionHandler _exceptionHandler;
  Parser _parser;
  Zone _zone;
  num _ttl;
  String _phase;
  Map<String, Object> _properties = {};
  List<Function> _innerAsyncQueue;
  List<Function> _outerAsyncQueue;
  List<_Watch> _watchers = [];
  Map<String, List<Function>> _listeners = {};
  Scope _nextSibling, _prevSibling, _childHead, _childTail;
  bool _isolate = false;
  Profiler _perf;


  Scope(ExceptionHandler this._exceptionHandler, Parser this._parser,
      ScopeDigestTTL ttl, Zone this._zone, Profiler this._perf) {
    _properties[r'this']= this;
    _ttl = ttl.ttl;
    $root = this;
    $id = '_${$root._nextId++}';
    _innerAsyncQueue = [];
    _outerAsyncQueue = [];

    // Set up the zone to auto digest this scope.
    _zone.onTurnDone = $digest;
    _zone.onError = (e, s, ls) => _exceptionHandler(e, s);
  }

  Scope._child(Scope this.$parent, bool this._isolate, Profiler this._perf) {
    _exceptionHandler = $parent._exceptionHandler;
    _parser = $parent._parser;
    _ttl = $parent._ttl;
    _properties[r'this'] = this;
    _zone = $parent._zone;
    $root = $parent.$root;
    $id = '_${$root._nextId++}';
    _innerAsyncQueue = $parent._innerAsyncQueue;
    _outerAsyncQueue = $parent._outerAsyncQueue;

    _prevSibling = $parent._childTail;
    if ($parent._childHead != null) {
      $parent._childTail._nextSibling = this;
      $parent._childTail = this;
    } else {
      $parent._childHead = $parent._childTail = this;
    }
  }

  _identical(a, b) =>
    identical(a, b) ||
    (a is String && b is String && a == b) ||
    (a is num && b is num && a.isNaN && b.isNaN);

  containsKey(String name) => this[name] != null;
  remove(String name) => this._properties.remove(name);
  operator []=(String name, value) => _properties[name] = value;
  operator [](String name) {
    if (name == r'$id') return this.$id;
    if (name == r'$parent') return this.$parent;
    if (name == r'$root') return this.$root;
    var scope = this;
    do {
      if (scope._properties.containsKey(name)) {
        return scope._properties[name];
      } else if (!scope._isolate) {
        scope = scope.$parent;
      } else {
        return null;
      }
    } while(scope != null);
    return null;
  }

  noSuchMethod(Invocation invocation) {
    var name = MirrorSystem.getName(invocation.memberName);
    if (invocation.isGetter) {
      return this[name];
    } else if (invocation.isSetter) {
      var value = invocation.positionalArguments[0];
      name = name.substring(0, name.length - 1);
      this[name] = value;
      return value;
    } else {
      if (this[name] is Function) {
        return this[name]();
      } else {
        super.noSuchMethod(invocation);
      }
    }
  }



  $new([bool isolate = false]) {
    return new Scope._child(this, isolate, _perf);
  }


  $watch(watchExp, [Function listener, String watchStr]) {
    if (watchStr == null) {
      watchStr = watchExp.toString();
      // print("CKCK: $watchStr");

      // Keep prod fast
      assert((() {

        //ckck
        if (watchExp is Function) {
          watchStr = "${watchExp.hashCode}";
        }
        return true;
        //ckck

        if (watchExp is Function) {
            watchStr = "FN: ${m.function.source}";
          var m = reflect(watchExp);
          if (m is ClosureMirror) {
            // work-around dartbug.com/14130
            try {
              watchStr = "FN: ${m.function.source}";
            } on NoSuchMethodError catch (e) {}

          }
        }
        return true;
      })());
    }
    var watcher = new _Watch(_compileToFn(listener), _initWatchVal,
        _compileToFn(watchExp), watchStr);

    // we use unshift since we use a while loop in $digest for speed.
    // the while loop reads in reverse order.
    _watchers.insert(0, watcher);

    return () => _watchers.remove(watcher);
  }

  $watchCollection(obj, listener) {
    var oldValue;
    var newValue;
    num changeDetected = 0;
    Function objGetter = _compileToFn(obj);
    List internalArray = [];
    Map internalMap = {};
    num oldLength = 0;

    var $watchCollectionWatch = (_) {
      newValue = objGetter(this);
      var newLength, key;

      if (newValue is! Map && newValue is! List) {
        if (!_identical(oldValue, newValue)) {
          oldValue = newValue;
          changeDetected++;
        }
      } else if (newValue is List) {
        if (!_identical(oldValue, internalArray)) {
          // we are transitioning from something which was not an array into array.
          oldValue = internalArray;
          oldLength = oldValue.length = 0;
          changeDetected++;
        }

        newLength = newValue.length;

        if (oldLength != newLength) {
          // if lengths do not match we need to trigger change notification
          changeDetected++;
          oldValue.length = oldLength = newLength;
        }
        // copy the items to oldValue and look for changes.
        for (var i = 0; i < newLength; i++) {
          if (!_identical(oldValue[i], newValue[i])) {
            changeDetected++;
            oldValue[i] = newValue[i];
          }
        }
      } else { // Map
        if (!_identical(oldValue, internalMap)) {
          // we are transitioning from something which was not an object into object.
          oldValue = internalMap = {};
          oldLength = 0;
          changeDetected++;
        }
        // copy the items to oldValue and look for changes.
        newLength = 0;
        newValue.forEach((key, value) {
          newLength++;
          if (oldValue.containsKey(key)) {
            if (!_identical(oldValue[key], value)) {
              changeDetected++;
              oldValue[key] = value;
            }
          } else {
            oldLength++;
            oldValue[key] = value;
            changeDetected++;
          }

        });
        if (oldLength > newLength) {
          // we used to have more keys, need to find them and destroy them.
          changeDetected++;
          var keysToRemove = [];
          oldValue.forEach((key, _) {
            if (!newValue.containsKey(key)) {
              oldLength--;
              keysToRemove.add(key);
            }
          });
          keysToRemove.forEach((k) {
            oldValue.remove(k);
          });
        }
      }
      return changeDetected;
    };

    var $watchCollectionAction = (_, __, ___) {
      relaxFnApply(listener, [newValue, oldValue, this]);
    };

    return this.$watch($watchCollectionWatch, $watchCollectionAction);
  }


  /**
   * Add this function to your code if you want to add a $digest
   * and want to assert that the digest will be called on this turn.
   * This method will be deleted when we are comfortable with
   * auto-digesting scope.
   */
  $$verifyDigestWillRun() {
    _zone.assertInTurn();
  }

  $digest() => _perf.time('angular.scope.digest', () {
    var innerAsyncQueue = _innerAsyncQueue,
        length,
        dirty, _ttlLeft = _ttl,
        logIdx, logMsg;
    List<List<String>> watchLog = [];
    List<_Watch> watchers;
    _Watch watch;
    Scope next, current, target = this;

    _beginPhase('\$digest');
    try {
      do { // "while dirty" loop
        dirty = false;
        current = target;
        //asyncQueue = current._asyncQueue;
        //dump('aQ: ${asyncQueue.length}');

        while(innerAsyncQueue.length > 0) {
          try {
            $root.$eval(innerAsyncQueue.removeAt(0));
          } catch (e, s) {
            _exceptionHandler(e, s);
          }
        }

        do { // "traverse the scopes" loop
          if ((watchers = current._watchers) != null) {
            // process our watches
            length = watchers.length;
            while (length-- > 0) {
              try {
                watch = watchers[length];
                var value = watch.get(current);
                var last = watch.last;
                if (!_identical(value, last)) {
                  dirty = true;
                  watch.last = value;
                  watch.fn(value, ((last == _initWatchVal) ? value : last), current);
                  if (_ttlLeft < 5) {
                    logIdx = 4 - _ttlLeft;
                    while (watchLog.length <= logIdx) {
                      watchLog.add([]);
                    }
                    logMsg = (watch.exp is Function)
                        ? 'fn: ' + (watch.exp.toString())
                        : watch.exp;
                    logMsg += '; newVal: ' + _toJson(value) + '; oldVal: ' + _toJson(last);
                    watchLog[logIdx].add(logMsg);
                  }
                }
              } catch (e, s) {
                _exceptionHandler(e, s);
              }
            }
          }

          // Insanity Warning: scope depth-first traversal
          // yes, this code is a bit crazy, but it works and we have tests to prove it!
          // this piece should be kept in sync with the traversal in $broadcast
          if (current._childHead == null) {
            if (current == target) {
              next = null;
            } else {
              next = current._nextSibling;
              if (next == null) {
                while(current != target && (next = current._nextSibling) == null) {
                  current = current.$parent;
                }
              }
            }
          } else {
            next = current._childHead;
          }
        } while ((current = next) != null);

        if(dirty && (_ttlLeft--) == 0) {
          throw '$_ttl \$digest() iterations reached. Aborting!\n' +
              'Watchers fired in the last 5 iterations: ${_toJson(watchLog)}';
        }
      } while (dirty || innerAsyncQueue.length > 0);
      while(_outerAsyncQueue.length > 0) {
        try {
          $root.$eval(_outerAsyncQueue.removeAt(0));
        } catch (e, s) {
          _exceptionHandler(e, s);
        }
      }
    } finally {
      _clearPhase();
    }
  });


  $destroy() {
    if ($root == this) return; // we can't remove the root node;

    $broadcast(r'$destroy');

    if ($parent._childHead == this) $parent._childHead = _nextSibling;
    if ($parent._childTail == this) $parent._childTail = _prevSibling;
    if (_prevSibling != null) _prevSibling._nextSibling = _nextSibling;
    if (_nextSibling != null) _nextSibling._prevSibling = _prevSibling;
  }


  $eval(expr, [locals]) {
    return relaxFnArgs(_compileToFn(expr))(this, locals);
  }


  $evalAsync(expr, {outsideDigest: false}) {
    if (outsideDigest) {
      _outerAsyncQueue.add(expr);
    } else {
      _innerAsyncQueue.add(expr);
    }
  }


  $apply([expr]) {
    return _zone.run(() {
      try {
        return $eval(expr);
      } catch (e, s) {
        _exceptionHandler(e, s);
      }
    });
  }


  $on(name, listener) {
    var namedListeners = _listeners[name];
    if (!_listeners.containsKey(name)) {
      _listeners[name] = namedListeners = [];
    }
    namedListeners.add(listener);

    return () {
      namedListeners.remove(listener);
    };
  }


  $emit(name, [List args]) {
    var empty = [],
        namedListeners,
        scope = this,
        event = new ScopeEvent(name, this),
        listenerArgs = [event],
        i;

    if (args != null) {
      listenerArgs.addAll(args);
    }

    do {
      namedListeners = scope._listeners[name];
      if (namedListeners != null) {
        event.currentScope = scope;
        i = 0;
        for (var length = namedListeners.length; i<length; i++) {
          try {
            relaxFnApply(namedListeners[i], listenerArgs);
            if (event.propagationStopped) return event;
          } catch (e, s) {
            _exceptionHandler(e, s);
          }
        }
      }
      //traverse upwards
      scope = scope.$parent;
    } while (scope != null);

    return event;
  }


  $broadcast(String name, [List listenerArgs]) {
    var target = this,
        current = target,
        next = target,
        event = new ScopeEvent(name, this);

    //down while you can, then up and next sibling or up and next sibling until back at root
    if (listenerArgs == null) {
      listenerArgs = [];
    }
    listenerArgs.insert(0, event);
    do {
      current = next;
      event.currentScope = current;
      if (current._listeners.containsKey(name)) {
        current._listeners[name].forEach((listener) {
          try {
            relaxFnApply(listener, listenerArgs);
          } catch(e, s) {
            _exceptionHandler(e, s);
          }
        });
      }

      // Insanity Warning: scope depth-first traversal
      // yes, this code is a bit crazy, but it works and we have tests to prove it!
      // this piece should be kept in sync with the traversal in $broadcast
      if (current._childHead == null) {
        if (current == target) {
          next = null;
        } else {
          next = current._nextSibling;
          if (next == null) {
            while(current != target && (next = current._nextSibling) == null) {
              current = current.$parent;
            }
          }
        }
      } else {
        next = current._childHead;
      }
    } while ((current = next) != null);

    return event;
  }

  _beginPhase(phase) {
    if ($root._phase != null) {
      // TODO(deboer): Remove the []s when dartbug.com/11999 is fixed.
      throw ['${$root._phase} already in progress'];
    }

    $root._phase = phase;
  }

  _clearPhase() {
    $root._phase = null;
  }

  Function _compileToFn(exp) {
    if (exp == null) {
      return () => null;
    } else if (exp is String) {
      return _parser(exp).eval;
    } else if (exp is Function) {
      return exp;
    } else {
      throw 'Expecting String or Function';
    }
  }
}

var _initWatchVal = new Object();

class _Watch {
  Function fn;
  dynamic last;
  Function get;
  String exp;

  _Watch(fn, this.last, getFn, this.exp) {
    this.fn = relaxFnArgs3(fn);
    this.get = relaxFnArgs1(getFn);
  }
}

_toJson(obj) {
  try {
    return stringify(obj);
  } catch(e) {
    var ret = "NOT-JSONABLE";
    // Keep prod fast.
    assert((() {
      var mirror = reflect(obj);
      if (mirror is ClosureMirror) {
        // work-around dartbug.com/14130
        try {
          ret = mirror.function.source;
        } on NoSuchMethodError catch (e) {}
      }
      return true;
    })());
    return ret;
  }
}
library angular.playback.playback_data;

// During HTTP playback, this file will be replaced with a file
// that has playback data.

Map playbackData = { };
library dart_code_gen_source;

import 'dart_code_gen.dart';

class SourceBuilder {
  static RegExp NON_WORDS = new RegExp(r'\W');

  Map<String, Code> refs = {};
  List<Code> codeRefs = [];

  String str(String s) => '\'' + s.replaceAll('\'', '\\\'').replaceAll(r'$', r'\$') + '\'';
  String ident(String s) => '_${s.replaceAll(NON_WORDS, '_')}_${s.hashCode}';

  String ref(Code code) {
    if (!refs.containsKey(code.id)) {
      refs[code.id] = code;
      code.toSource(this); // recursively expand;
      codeRefs.add(code);
    }
    return this.ident(code.id);
  }

  parens([p1, p2, p3, p4, p5, p6]) => new ParenthesisSource()..call(p1, p2, p3, p4, p5, p6);
  body([p1, p2, p3, p4, p5, p6]) => new BodySource()..call(p1, p2, p3, p4, p5, p6);
  stmt([p1, p2, p3, p4, p5, p6]) => new StatementSource()..call(p1, p2, p3, p4, p5, p6);

  call([p1, p2, p3, p4, p5, p6]) => new Source()..call(p1, p2, p3, p4, p5, p6);

}

class Source {
  static String NEW_LINE = '\n';
  List source = [];

  call([p1, p2, p3, p4, p5, p6]) {
    if (p1 != null) source.add(p1);
    if (p2 != null) source.add(p2);
    if (p3 != null) source.add(p3);
    if (p4 != null) source.add(p4);
    if (p5 != null) source.add(p5);
    if (p6 != null) source.add(p6);
  }

  toString([String indent='', newLine=false, sep='']) {
    var lines = [];
    var trailing = sep == ';';
    var _sep = '';
    source.forEach((s) {
      if (!trailing) lines.add(_sep);
      if (newLine) lines.add('\n' + indent);
      if (s is Source) {
        lines.add(s.toString(indent));
      } else {
        lines.add(s);
      }
      _sep = sep;
      if (trailing) lines.add(_sep);
    });
    return lines.join('');
  }
}


class ParenthesisSource extends Source {
  toString([String indent='']) {
    return '(' + super.toString(indent + '  ', true, ',') + ')';
  }
}

class MapSource extends Source {
  toString([String indent='']) {
    return '{' + super.toString(indent + '  ', true, ',') + '}';
  }
}

class BodySource extends Source {
  BodySource() {
    //this('');
  }
  toString([String indent='']) {
    return '{' + super.toString(indent + '  ', true) + '\n$indent}';
  }
}

class StatementSource extends Source {
  toString([String indent='']) {
    return '${super.toString(indent + '  ')};';
  }
}
library angular.perf;

import 'package:di/di.dart';
import 'package:perf_api/perf_api.dart';

class NgPerfModule extends Module {
  NgPerfModule() {
    type(Profiler);
  }
}
part of angular.directive;

typedef dynamic ItemEval(dynamic item, num index);

/**
 * HTML [SELECT] element with angular data-binding if used with [NgModelDirective].
 *
 * The [NgModelDirective] will receive the currently selected item. The binding is
 * performed on the [OPTION].[value] property.
 * An empty [OPTION].[value] is treated as null.
 *
 * If you the model contains value which does not map to any [OPTION] then a new
 * unknown [OPTION] is inserted into the list. Once the model points to an existing
 * [OPTION] the unknown [OPTION] is removed.
 *
 * Becouse [OPTION].[value] attribute is a string, the model is bound to a string.
 * If there is need to bind to an object then [OptionValueDirective] should be used.
 *
 */
@NgDirective(
    selector: 'select[ng-model]',
    visibility: NgDirective.CHILDREN_VISIBILITY
)
class InputSelectDirective implements NgAttachAware {
  final Expando<OptionValueDirective> expando = new Expando<OptionValueDirective>();
  final dom.SelectElement _selectElement;
  final NodeAttrs _attrs;
  final NgModel _model;
  final Scope _scope;

  final dom.OptionElement _unknownOption = new dom.OptionElement();
  dom.OptionElement _nullOption;

  _SelectMode _mode = new _SelectMode(null, null, null);
  bool _dirty = false;

  InputSelectDirective(dom.Element this._selectElement,
                       NodeAttrs this._attrs,
                       NgModel this._model,
                       Scope this._scope) {
    _unknownOption.value = '?';
    _selectElement.queryAll('option').forEach((o) {
      if (_nullOption == null && o.value == '') {
        _nullOption = o;
      }
    });
  }

  attach() {
    _attrs.observe('multiple', (value) {
      _mode.destroy();
      if (value == null) {
        _model.watchCollection = false;
        _mode = new _SingleSelectMode(expando, _selectElement, _model, _nullOption, _unknownOption);
      } else {
        _model.watchCollection = true;
        _mode = new _MultipleSelectionMode(expando, _selectElement, _model);
      }
      _mode.onModelChange(_model.viewValue);
    });

    _selectElement.onChange.listen((event) => _mode.onViewChange(event));
    _model.render = (value) => _mode.onModelChange(value);
  }

  /**
   * This method invalidates the current state of the selector and forces a rerendering of the
   * options using the [Scope.$evalAsync].
   */
  dirty() {
    if (!_dirty) {
      _dirty = true;
      _scope.$evalAsync(() {
        _dirty = false;
        _mode.onModelChange(_model.viewValue);
      });
    }
  }
}

/**
 * Since the [value] attirbute of the [OPTION] can only be a string, Angular provides
 * [ng-value] which allows binding to any expression.
 *
 */
@NgDirective(
    selector: 'option',
    publishTypes: const [TextChangeListener],
    map: const {'ng-value': '&.ngValue'}
)
class OptionValueDirective implements TextChangeListener, NgAttachAware, NgDetachAware {
  final InputSelectDirective _inputSelectDirective;
  final NodeAttrs _attrs;

  Getter _ngValue;

  OptionValueDirective(NodeAttrs this._attrs,
                       InputSelectDirective this._inputSelectDirective) {
    if (_inputSelectDirective != null) {
      _inputSelectDirective.expando[_attrs.element] = this;
    }
  }

  attach() {
    if (_inputSelectDirective != null) {
      this._attrs.observe('value', (_) => _inputSelectDirective.dirty());
    }
  }

  call(String text) {
    if (_inputSelectDirective != null) {
      _inputSelectDirective.dirty();
    }
  }

  detach() {
    if (_inputSelectDirective != null) {
      _inputSelectDirective.dirty();
      _inputSelectDirective.expando[_attrs.element] = null;
    }
  }

  set ngValue(Getter value) => _ngValue = value;
  get ngValue {
    return _attrs['ng-value'] is String ? _ngValue() : (_attrs.element as dom.OptionElement).value;
  }
}

class _SelectMode {
  final Expando<OptionValueDirective> expando;
  final dom.SelectElement select;
  final NgModel model;

  _SelectMode(Expando<OptionValueDirective> this.expando,
              dom.SelectElement this.select,
              NgModel this.model);

  onViewChange(event) {}
  onModelChange(value) {}
  destroy() {}

  get _options => select.queryAll('option');
  _forEachOption(fn, [quiteOnReturn = false]) {
    for(var os = _options, i = 0, ii = os.length; i < ii; i++) {
      var retValue = fn(os[i], i);
      if (quiteOnReturn && retValue != null) {
        return retValue;
      }
    }
    return null;
  }
}

class _SingleSelectMode extends _SelectMode {
  final dom.OptionElement _unknownOption;
  final dom.OptionElement _nullOption;

  bool _unknownOptionActive = false;

  _SingleSelectMode(Expando<OptionValueDirective> expando,
                    dom.SelectElement select,
                    NgModel model,
                    dom.OptionElement this._nullOption,
                    dom.OptionElement this._unknownOption
                    ): super(expando, select, model) {
  }

  onViewChange(event) {
    var i = 0;
    model.viewValue = _forEachOption((option, _) {
      if (option.selected) {
        return option == _nullOption ? null : expando[option].ngValue;
      }
      if (option != _unknownOption && option != _nullOption) {
        i++;
      }
    }, true);
  }

  onModelChange(value) {
    var found = false;
    _forEachOption((option, i) {
      if (option == _unknownOption) return;
      var selected = value == null ? option == _nullOption : expando[option].ngValue == value;
      found = found || selected;
      option.selected = selected;
    });

    if (!found) {
      if (!_unknownOptionActive) {
        select.insertBefore(_unknownOption, select.firstChild);
        _unknownOption.selected = true;
        _unknownOptionActive = true;
      }
    } else {
      if (_unknownOptionActive) {
        _unknownOption.remove();
        _unknownOptionActive = false;
      }
    }
  }
}

class _MultipleSelectionMode extends _SelectMode {
  _MultipleSelectionMode(Expando<OptionValueDirective> expando,
                         dom.SelectElement select,
                         NgModel model
                         ): super(expando, select, model);

  onViewChange(event) {
    var selected = [];
    var fn = (o, i) => o.value;

    _forEachOption((o, i) {
      if (o.selected) {
        selected.add(expando[o].ngValue);
      }
    });
    model.viewValue = selected;
  }

  onModelChange(List selectedValues) {
    num index = 0;
    Function fn = (o, i) => o.selected = null;

    if (selectedValues is List) {
      fn = (o, i) => o.selected = selectedValues.contains(expando[o].ngValue);
    }

    _forEachOption(fn);
  }
}
library generator;

import 'dart_code_gen.dart';
import '../../core/parser/parser_library.dart';
import 'source.dart';

class ParserGenerator {
  DynamicParser _parser;
  Map<String, boolean> _printedFunctions = {};
  GetterSetterGenerator _getters;
  SourceBuilder _ = new SourceBuilder();

  ParserGenerator(DynamicParser this._parser,
                  GetterSetterGenerator this._getters);

  generateParser(List<String> expressions) {
    print("genEvalError(msg) { throw msg; }");
    print("functions(FilterLookup filters) => new StaticParserFunctions(buildExpressions(filters));");
    print('var evalError = (text, [s]) => text;');
    print("");
    BodySource body = new BodySource();
    MapSource map = new MapSource();

    // deterimine the order.
    expressions.forEach((exp) {
      var code = safeCode(exp);
      map('${_.str(exp)}: ${_.ref(code)}');
    });
    // now do it in actual order
    _.codeRefs.forEach((code) {
      body(_.stmt('Expression ${_.ref(code)} = ', code.toSource(_)));
    });
    body(_.stmt('return ', map));
    print("Map<String, Expression> buildExpressions(FilterLookup filters) ${body}");
    print("\n");
    print(_getters.functions);
  }

  String generateDart(String expression) {
    var tokens = _lexer(expression);
  }


  Code safeCode(String exp) {
    try {
      return _parser(exp);
    } catch (e) {
      if ("$e".contains('Parser Error') ||
      "$e".contains('Lexer Error') ||
      "$e".contains('Unexpected end of expression')) {
        return  new ThrowCode("'${escape(e.toString())}';");
      } else {
        rethrow;
      }
    }
  }

}
part of angular.core.dom;

/**
 * Infinite cache service for templates loaded from URLs.
 * 
 * All templates that are loaded from a URL are cached indefinitely in the
 * TemplateCache the first time they are needed.  This includes templates loaded
 * via `ng-include` or via the `templateUrl` field on components decorated with
 * [NgComponent].
 *
 * All attempts that require loading a template from a URL are first checked
 * against this cache.  Only when there is a cache miss is a network request
 * attempted.
 *
 * You are welcome to pre-load / seed the TemplateCache with templates for URLs
 * in advance to avoid the network hit on first load.
 *
 * There are two ways to seed the TemplateCache – (1) imperatively via and
 * `TemplateCache` service or (2) declaratively in HTML via the `<template>`
 * element (handled by [NgTemplateElementDirective]).
 *
 * Here is an example that illustrates both techniques
 * ([view in plunker](http://plnkr.co/edit/JCsxhH?p=info)):
 *
 * Example:
 * 
 *     // main.dart
 *     import 'package:angular/angular.dart';
 * 
 *     @NgDirective(selector: '[main-controller]')
 *     class LoadTemplateCacheDirective {
 *       LoadTemplateCacheDirective(TemplateCache templateCache, Scope scope) {
 *         // Method 1 (imperative): Via the injected TemplateCache service.
 *         templateCache.put(
 *             'template_1.html', new HttpResponse(200, 't1: My name is {{name}}.'));
 *         scope.name = "chirayu";
 *       }
 *     }
 *
 *     main() {
 *       bootstrapAngular([new AngularModule()..type(LoadTemplateCacheDirective)], 'html');
 *     }
 *
 * and
 *
 *     <!-- index.html -->
 *     <html>
 *       <head>
 *         <script src="packages/browser/dart.js"></script>
 *         <script src="main.dart" type="application/dart"></script>
 *
 *         <!-- Method 2 (declarative): Via the template directive. -->
 *         <template id="template_2.html" type="text/ng-template">
 *           t2: My name is {{name}}.
 *         </template>
 *       </head>
 *       <body load-template-cache>
 *         template_1.html: <div ng-include="'template_1.html'"></div><br>
 *         template_2.html: <div ng-include="'template_2.html'"></div><br>
 *       </body>
 *     </html>
 *
 * Neither `ng-include` above will result in a network hit.  This means that it
 * isn't necessary for your webserver to even serve those templates.
 *
 * `template_1.html` is preloaded into the [TemplateCache] imperatively by
 * `LoadTemplateCacheDirective` while `template_2.html` is preloaded via the
 * `<template id="template_2.html" type="text/ng-template">` element
 * declaratively in the `<head>` of HTML.
 */
class TemplateCache extends LruCache<String, HttpResponse> {
  TemplateCache({int capacity}): super(capacity: capacity);
}
library di.injector;

import 'module.dart';

abstract class Injector {

  /**
   * Returns the name of the injector or null of none is given.
   */
  String get name;

  /**
   * Returns the parent injector or null if root.
   */
  Injector get parent;

  /**
   * Get an instance for given token ([Type]).
   *
   * If the injector already has an instance for this token, it returns this
   * instance. Otherwise, injector resolves all its dependencies, instantiate
   * new instance and returns this instance.
   *
   * If there is no binding for given token, injector asks parent injector.
   *
   * If there is no parent injector, an implicit binding is used. That is,
   * the token ([Type]) is instantiated.
   */
  dynamic get(Type type);

  /**
   * Return a list of all types which the injector can return
   */
  Set<Type> get types;

  /**
   * Create a child injector.
   *
   * Child injector can override any bindings by adding additional modules.
   *
   * It also accepts a list of tokens that a new instance should be forced.
   * That means, even if some parent injector already has an instance for this
   * token, there will be a new instance created in the child injector.
   */
  Injector createChild(List<Module> modules, {List<Type> forceNewInstances,
                                              String name});
}
part of angular.core;

class CacheStats {
  final int capacity;
  final int size;
  final int hits;
  final int misses;
  CacheStats(int this.capacity, int this.size, int this.hits, int this.misses);
  String toString() =>
      "[CacheStats: capacity: $capacity, size: $size, hits: $hits, misses: $misses]";
}


/**
 * The Cache interface.
 */
abstract class Cache<K, V> {
  /**
   * Returns the value for `key` from the cache.  If `key` is not in the cache,
   * returns `null`.
   */
  V get(K key);
  /**
   * Inserts/Updates the `key` in the cache with `value` and returns the value.
   */
  V put(K key, V value);
  /**
   * Removes `key` from the cache.  If `key` isn't present in the cache, does
   * nothing.
   */
  V remove(K key);
  /**
   * Removes all entries from the cache.
   */
  void removeAll();
  int get capacity;
  int get size;
  CacheStats stats();
}


/**
 * An unbounded cache.
 */
class UnboundedCache<K, V> implements Cache<K, V> {
  Map<K, V> _entries = <K, V>{};
  int _hits = 0;
  int _misses = 0;

  V get(K key) {
    V value = _entries[key];
    if (value != null || _entries.containsKey(key)) {
      ++_hits;
    } else {
      ++_misses;
    }
    return value;
  }
  V put(K key, V value) => _entries[key] = value;
  V remove(K key) => _entries.remove(key);
  void removeAll() => _entries.clear();
  int get capacity => 0;
  int get size => _entries.length;
  CacheStats stats() => new CacheStats(capacity, size, _hits, _misses);
  // Debugging helper.
  String toString() => "[$runtimeType: size=${_entries.length}, items=$_entries]";
}


/**
 * Simple LRU cache.
 *
 * TODO(chirayu):
 * - add docs
 * - add tests
 * - should stringify keys?
 */
class LruCache<K, V> extends Cache<K, V> {
  Map<K, V> _entries = new LinkedHashMap<K, V>();
  int _capacity;
  int _hits = 0;
  int _misses = 0;

  LruCache({int capacity}) {
    this._capacity = (capacity == null) ? 0 : capacity;
  }

  V get(K key) {
    V value = _entries[key];
    if (value != null || _entries.containsKey(key)) {
      ++_hits;
      // refresh
      _entries.remove(key);
      _entries[key] = value;
    } else {
      ++_misses;
    }
    return value;
  }

  V put(K key, V value) {
    // idempotent.  needed to refresh an existing key.
    _entries.remove(key);
    // _capacity always > 0 but might not be true in some future.
    if (_capacity > 0 && _capacity == _entries.length) {
      // drop oldest entry when at capacity
      // _entries.keys.first is fairly cheap - 2 new calls.
      _entries.remove(_entries.keys.first);
    }
    _entries[key] = value;
    return value;
  }

  V remove(K key) => _entries.remove(key);
  void removeAll() => _entries.clear();
  int get capacity => _capacity;
  int get size => _entries.length;
  CacheStats stats() => new CacheStats(capacity, size, _hits, _misses);
  // Debugging helper.
  String toString() => "[$runtimeType: capacity=$capacity, size=$size, items=$_entries]";
}
part of angular.core.dom;

/**
 * DirectiveSelector is a function which given a node it will return a
 * list of [DirectiveRef]s which are triggered by this node.
 *
 * DirectiveSelector is used by the [Compiler] during the template walking
 * to extract the [DirectiveRef]s.
 *
 * DirectiveSelector can be created using the [directiveSelectorFactory]
 * method.
 *
 * The DirectiveSelector supports CSS selectors which do not cross
 * element boundaries only. The selectors can have any mix of element-name,
 * class-names and attribute-names.
 *
 * Examples:
 *
 * <pre>
 *   element
 *   .class
 *   [attribute]
 *   [attribute=value]
 *   element[attribute1][attribute2=value]
 * </pre>
 *
 *
 */
typedef List<DirectiveRef> DirectiveSelector(dom.Node node);

class _Directive {
  final Type type;
  final NgAnnotation annotation;

  _Directive(Type this.type, NgAnnotation this.annotation);
}


class _ContainsSelector {
  NgAnnotation annotation;
  RegExp regexp;

  _ContainsSelector(NgAnnotation this.annotation, String regexp) {
    this.regexp = new RegExp(regexp);
  }
}

RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|(?:\[([\w\-]+)(?:=([^\]]*))?\]))');
RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$');
RegExp _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); //
RegExp _ATTR_CONTAINS_REGEXP = new RegExp(r'^\[\*=\/(.+)\/\]$'); //

class _SelectorPart {
  final String element;
  final String className;
  final String attrName;
  final String attrValue;

  const _SelectorPart.fromElement(String this.element)
      : className = null, attrName = null, attrValue = null;

  const _SelectorPart.fromClass(String this.className)
      : element = null, attrName = null, attrValue = null;


  const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue)
      : element = null, className = null;

  toString() =>
    element == null
      ? (className == null
         ? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]')
         : '.$className')
      : element;
}


class _ElementSelector {
  String name;

  Map<String, _Directive> elementMap = new Map<String, _Directive>();
  Map<String, _ElementSelector> elementPartialMap = new Map<String, _ElementSelector>();

  Map<String, _Directive> classMap = new Map<String, _Directive>();
  Map<String, _ElementSelector> classPartialMap = new Map<String, _ElementSelector>();

  Map<String, Map<String, _Directive>> attrValueMap = new Map<String, Map<String, _Directive>>();
  Map<String, Map<String, _ElementSelector>> attrValuePartialMap = new Map<String, Map<String, _ElementSelector>>();

  _ElementSelector(String this.name);

  addDirective(List<_SelectorPart> selectorParts, _Directive directive) {
    var selectorPart = selectorParts.removeAt(0);
    var terminal = selectorParts.isEmpty;
    var name;
    if ((name = selectorPart.element) != null) {
      if (terminal) {
        elementMap[name] = directive;
      } else {
        elementPartialMap
            .putIfAbsent(name, () => new _ElementSelector(name))
            .addDirective(selectorParts, directive);
      }
    } else if ((name = selectorPart.className) != null) {
      if (terminal) {
        classMap[name] = directive;
      } else {
        classPartialMap
            .putIfAbsent(name, () => new _ElementSelector(name))
            .addDirective(selectorParts, directive);
      }
    } else if ((name = selectorPart.attrName) != null) {
      if (terminal) {
        attrValueMap
            .putIfAbsent(name, () => new Map<String, _Directive>())
            [selectorPart.attrValue] = directive;
      } else {
        attrValuePartialMap
            .putIfAbsent(name, () => new Map<String, _ElementSelector>())
            [selectorPart.attrValue] = new _ElementSelector(name)
                ..addDirective(selectorParts, directive);
      }
    } else {
      throw "Unknown selector part '$selectorPart'.";
    }
  }

  List<_ElementSelector> selectNode(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
             dom.Node node, String nodeName) {
    if (elementMap.containsKey(nodeName)) {
      _Directive directive = elementMap[nodeName];
      refs.add(new DirectiveRef(node, directive.type, directive.annotation));
    }
    if (elementPartialMap.containsKey(nodeName)) {
      if (partialSelection == null) partialSelection = new List<_ElementSelector>();
      partialSelection.add(elementPartialMap[nodeName]);
    }
    return partialSelection;
  }

  List<_ElementSelector> selectClass(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
         dom.Node node, String className) {
    if (classMap.containsKey(className)) {
      var directive = classMap[className];
      refs.add(new DirectiveRef(node, directive.type, directive.annotation));
    }
    if (classPartialMap.containsKey(className)) {
      if (partialSelection == null) partialSelection = new List<_ElementSelector>();
      partialSelection.add(classPartialMap[className]);
    }
    return partialSelection;
  }

  List<_ElementSelector> selectAttr(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
         dom.Node node, String attrName, String attrValue) {
    if (attrValueMap.containsKey(attrName)) {
      Map<String, _Directive> valuesMap = attrValueMap[attrName];
      if (valuesMap.containsKey('')) {
        _Directive directive = valuesMap[''];
        refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
      }
      if (attrValue != '' && valuesMap.containsKey(attrValue)) {
        _Directive directive = valuesMap[attrValue];
        refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
      }
    }
    if (attrValuePartialMap.containsKey(attrName)) {
      Map<String, _ElementSelector> valuesPartialMap = attrValuePartialMap[attrName];
      if (valuesPartialMap.containsKey('')) {
        if (partialSelection == null) partialSelection = new List<_ElementSelector>();
        partialSelection.add(valuesPartialMap['']);
      }
      if (attrValue != '' && valuesPartialMap.containsKey(attrValue)) {
        if (partialSelection == null) partialSelection = new List<_ElementSelector>();
        partialSelection.add(valuesPartialMap[attrValue]);
      }
    }
    return partialSelection;
  }

  toString() => 'ElementSelector($name)';
}

List<_SelectorPart> _splitCss(String selector) {
  List<_SelectorPart> parts = [];
  var remainder = selector;
  var match;
  while (!remainder.isEmpty) {
    if ((match = _SELECTOR_REGEXP.firstMatch(remainder)) != null) {
      if (match[1] != null) {
        parts.add(new _SelectorPart.fromElement(match[1].toLowerCase()));
      } else if (match[2] != null) {
        parts.add(new _SelectorPart.fromClass(match[2].toLowerCase()));
      } else if (match[3] != null) {
        var attrValue = match[4] == null ? '' : match[4].toLowerCase();
        parts.add(new _SelectorPart.fromAttribute(match[3].toLowerCase(),
                                                  attrValue));
      } else {
        throw "Missmatched RegExp $_SELECTOR_REGEXP on $remainder";
      }
    } else {
      throw "Unknown selector format '$remainder'.";
    }
    remainder = remainder.substring(match.end);
  }
  return parts;
}

/**
 *
 * Factory method for creating a [DirectiveSelector].
 */
DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {

  _ElementSelector elementSelector = new _ElementSelector('');
  List<_ContainsSelector> attrSelector = [];
  List<_ContainsSelector> textSelector = [];

  directives.forEach((NgAnnotation annotation, Type type) {
    var match;
    var selector = annotation.selector;
    List<_SelectorPart> selectorParts;

    if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
      textSelector.add(new _ContainsSelector(annotation, match.group(1)));
    } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
      attrSelector.add(new _ContainsSelector(annotation, match[1]));
    } else if ((selectorParts = _splitCss(selector)) != null){
      elementSelector.addDirective(selectorParts, new _Directive(type, annotation));
    } else {
      throw new ArgumentError('Unsupported Selector: $selector');
    }
  });

  return (dom.Node node) {
    List<DirectiveRef> directiveRefs = [];
    List<_ElementSelector> partialSelection = null;
    Map<String, bool> classes = new Map<String, bool>();
    Map<String, String> attrs = new Map<String, String>();

    switch(node.nodeType) {
      case 1: // Element
        dom.Element element = node;
        String nodeName = element.tagName.toLowerCase();
        Map<String, String> attrs = {};

        // Select node
        partialSelection = elementSelector.selectNode(directiveRefs, partialSelection, element, nodeName);

        // Select .name
        if ((element.classes) != null) {
          for(var name in element.classes) {
            classes[name] = true;
            partialSelection = elementSelector.selectClass(directiveRefs, partialSelection, element, name);
          }
        }

        // Select [attributes]
        element.attributes.forEach((attrName, value){
          attrs[attrName] = value;
          for(var k = 0, kk = attrSelector.length; k < kk; k++) {
            _ContainsSelector selectorRegExp = attrSelector[k];
            if (selectorRegExp.regexp.hasMatch(value)) {
              // this directive is matched on any attribute name, and so
              // we need to pass the name to the directive by prefixing it to the
              // value. Yes it is a bit of a hack.
              Type type = directives[selectorRegExp.annotation];
              directiveRefs.add(new DirectiveRef(
                  node, type, selectorRegExp.annotation, '$attrName=$value'));
            }
          }

          partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, attrName, value);
        });

        while(partialSelection != null) {
          List<_ElementSelector> elementSelectors = partialSelection;
          partialSelection = null;
          elementSelectors.forEach((_ElementSelector elementSelector) {
            classes.forEach((className, _) {
              partialSelection = elementSelector.selectClass(directiveRefs, partialSelection, node, className);
            });
            attrs.forEach((attrName, value) {
              partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, attrName, value);
            });
          });
        }
        break;
      case 3: // Text Node
        for(var value = node.nodeValue, k = 0, kk = textSelector.length; k < kk; k++) {
          var selectorRegExp = textSelector[k];

          if (selectorRegExp.regexp.hasMatch(value)) {
            Type type = directives[selectorRegExp.annotation];
            directiveRefs.add(new DirectiveRef(node, type, selectorRegExp.annotation, value));
          }
        }
        break;
      }

      directiveRefs.sort(_priorityComparator);
      return directiveRefs;
    };
}

int _directivePriority(NgAnnotation annotation) {
  if (annotation is NgDirective) {
    return (annotation.children == NgAnnotation.TRANSCLUDE_CHILDREN) ? 2 : 1;
  } else if (annotation is NgComponent) {
    return 0;
  }
  throw "Unexpected Type: ${annotation}.";
}

int _priorityComparator(DirectiveRef a, DirectiveRef b) {
  return _directivePriority(b.annotation) - _directivePriority(a.annotation);
}
library di.module;

import 'dart:collection';

import 'injector.dart';

typedef dynamic FactoryFn(Injector injector);

/**
 * Creation strategy is asked to return an instance of the type after
 * [Injector.get] locates the defining injector that has no instance cached.
 * [directInstantation] is true when an instance is created directly from
 * [Injector.instantiate].
 */
typedef dynamic CreationStrategy(
  Injector requesting,
  Injector defining,
  dynamic factory()
);

/**
 * Visibility determines if the instance in the defining module is visible to
 * the requesting injector. If true is returned, then the instance from the
 * defining injector is provided. If false is returned, the injector keeps
 * walking up the tree to find another visible instance.
 */
typedef bool Visibility(Injector requesting, Injector defining);


/**
 * A collection of type bindings. Once the module is passed into the injector,
 * the injector creates a copy of the module and all subsequent changes to the
 * module have no effect.
 */
class Module {
  final Map<Type, Binding> _bindings = new HashMap<Type, Binding>();
  final List<Module> _childModules = <Module>[];

  /**
   * Compiles and returs bindings map by performing depth-first traversal of the
   * child (installed) modules.
   */
  Map<Type, Binding> get bindings {
    Map<Type, Binding> res = new HashMap<Type, Binding>();
    _childModules.forEach((child) => res.addAll(child.bindings));
    res.addAll(_bindings);
    return res;
  }

  /**
   * Register binding to a concrete value.
   *
   * The [value] is what actually will be injected.
   */
  void value(Type id, value,
      {CreationStrategy creation, Visibility visibility}) {
    _bindings[id] = new ValueBinding(value, creation, visibility);
  }

  /**
   * Register binding to a [Type].
   *
   * The [implementedBy] will be instantiated using [new] operator and the
   * resulting instance will be injected. If no type is provided, then it's
   * implied that [id] should be instantiated.
   */
  void type(Type id, {Type implementedBy, CreationStrategy creation,
      Visibility visibility}) {
    _bindings[id] = new TypeBinding(implementedBy == null ? id : implementedBy,
        creation, visibility);
  }

  /**
   * Register binding to a factory function.abstract
   *
   * The [factoryFn] will be called and all its arguments will get injected.
   * The result of that function is the value that will be injected.
   */
  void factory(Type id, FactoryFn factoryFn,
      {CreationStrategy creation, Visibility visibility}) {
    _bindings[id] = new FactoryBinding(factoryFn, creation, visibility);
  }

  /**
   * Installs another module into this module. Bindings defined on this module
   * take precidence over the installed module.
   */
  void install(Module module) => _childModules.add(module);
}

/** Deafault creation strategy is to instantiate on the defining injector. */
dynamic _defaultCreationStrategy(Injector requesting, Injector defining,
    dynamic factory()) => factory();

/** By default all values are visible to child injectors. */
bool _defaultVisibility(_, __) => true;


abstract class Binding {
  final CreationStrategy creationStrategy;
  final Visibility visibility;

  Binding(_creationStrategy, _visibility)
      : creationStrategy = _creationStrategy == null ?
            _defaultCreationStrategy : _creationStrategy,
        visibility = _visibility == null ?
            _defaultVisibility : _visibility;
}

class ValueBinding extends Binding {
  final Object value;

  ValueBinding(this.value, [CreationStrategy creationStrategy,
                            Visibility visibility])
      : super(creationStrategy, visibility);
}

class TypeBinding extends Binding {
  final Type type;

  TypeBinding(this.type, [CreationStrategy creationStrategy,
                          Visibility visibility])
      : super(creationStrategy, visibility);
}

class FactoryBinding extends Binding {
  final FactoryFn factoryFn;

  FactoryBinding(this.factoryFn, [CreationStrategy creationStrategy,
                                  Visibility visibility])
      : super(creationStrategy, visibility);
}
library angular.mock;

import 'dart:async';
import 'dart:html';
import 'dart:json' as json;
import 'dart:mirrors' as mirror;
import 'dart:async' as dartAsync;
import '../angular.dart';
import '../utils.dart' as utils;
import 'package:js/js.dart' as js;
import 'package:di/di.dart';

part 'debug.dart';
part 'exception_handler.dart';
part 'http_backend.dart';
part 'log.dart';
part 'probe.dart';
part 'test_bed.dart';
part 'zone.dart';

/**
 * Use in addition to [AngularModule] in your tests.
 *
 * [AngularMockModule] provides:
 *
 *   - [TestBed]
 *   - [Probe]
 *   - [MockHttpBackend] instead of [HttpBackend]
 *   - [Logger]
 *   - [RethrowExceptionHandler] instead of [ExceptionHandler]
 *   - [ng.Zone] which displays errors to console;
 */
class AngularMockModule extends Module {
  AngularMockModule() {
    type(ExceptionHandler, implementedBy: RethrowExceptionHandler);
    type(TestBed);
    type(Probe);
    type(Logger);
    type(MockHttpBackend);
    factory(HttpBackend, (Injector i) => i.get(MockHttpBackend));
    factory(Zone, (_) {
      Zone zone = new Zone();
      zone.onError = (dynamic e, dynamic s, LongStackTrace ls) => dump('EXCEPTION: $e\n$s\n$ls');
      return zone;
    });
  }
}
part of angular.filter;

typedef dynamic Mapper(dynamic e);

/**
 * Orders the provided [Iterable] by the `expression` predicate.
 *
 * Example 1: Simple array and single/empty expression.
 *
 * Assume that you have an array on scope called `colors` and that it has a list
 * of these strings – `['red', 'blue', 'green']`.  You might sort these in
 * ascending order this way:
 *
 *     Colors: <ul>
 *       <li ng-repeat="color in colors | orderBy:''">{{color}}</li>
 *     </ul>
 *
 * That would result in:
 *
 *     <ul>
 *       <li>blue</li>
 *       <li>green</li>
 *       <li>red</li>
 *     <ul>
 *
 * The empty string expression, `''`, here signifies sorting in ascending order
 * using the default comparator.  Using `'+'` would also work as the `+` prefix
 * is implied.
 *
 * To sort in descending order, you would use the `'-'` prefix.
 *
 *     Colors: <ul>
 *       <li ng-repeat="color in colors | orderBy:'-'">{{color}}</li>
 *     </ul>
 *
 * For this simple example, you could have also provided `true` as the addition
 * optional parameter which requests a reverse order sort to get the same
 * result.
 *
 *     <!-- Same result (descending order) as previous snippet. -->
 *     Colors: <ul>
 *       <li ng-repeat="color in colors | orderBy:'':true">{{color}}</li>
 *     </ul>
 *
 * Example 2: Complex objects, single expression.
 *
 * You may provide a more complex expression to sort non-primitives values or
 * if you want to sort on a decorated/transformed value.
 *
 * e.g. Support you have a list `users` that looks like this:
 *
 *     authors = [
 *       {firstName: 'Emily',   lastName: 'Bronte'},
 *       {firstName: 'Mark',    lastName: 'Twain'},
 *       {firstName: 'Jeffrey', lastName: 'Archer'},
 *       {firstName: 'Isaac',   lastName: 'Asimov'},
 *       {firstName: 'Oscar',   lastName: 'Wilde'},
 *     ];
 *
 * If you want to list the authors sorted by `lastName`, you would use
 *
 *     <li ng-repeat="author in authors | orderBy:'lastName'">
 *       {{author.lastName}}, {{author.firstName
 *     </li>
 *
 * The string expression, `'lastName'`, indicates that the sort should be on the
 * `lastName` property of each item.
 *
 * Using the lesson from the previous example, you may sort in reverse order of
 * lastName using either of the two methods.
 *
 *     <!-- reverse order of last names -->
 *     <li ng-repeat="author in authors | orderBy:'-lastName'">
 *     <!-- also does the same thing -->
 *     <li ng-repeat="author in authors | orderBy:'lastName':true">
 *
 * Note that, while we only discussed string expressions, such as `"lastName"`
 * or the empty string, you can also directly provide a custom callable that
 * will be called to transform the element before a sort.
 *
 *     <li ng-repeat="author in authors | orderBy:getAuthorId">
 *
 * In the previous snippet, `getAuthorId` would evaluate to a callable when
 * evaluated on the [Scope] of the `<li>` element.  That callable is called once
 * for each element in the list (i.e. each author object) and the sort order is
 * determined by the sort order of the value mapped by the callable.
 *
 * Example 3: List expressions
 *
 * Both a string expression and the callable expression are simple versions of
 * the more general list expression.  You may pass a list as the orderBy
 * expression and this list may consist of either of the string or callable
 * expressions you saw in the previous examples.  A list expression indicates
 * a list of fallback expressions to use when a comparision results in the items
 * being equal.
 *
 * For example, one might want to sort the authors list, first by last name and
 * then by first name when the last names are equal.  You would do that like
 * this:
 *
 *     <li ng-repeat="author in authors | orderBy:['lastName', 'firstName']">
 *
 * The items in such a list may either be string expressions or callables.  The
 * list itself might be provided as an expression that is looked up on the scope
 * chain.
 */
@NgFilter(name: 'orderBy')
class OrderByFilter {
  Parser _parser;

  OrderByFilter(Parser this._parser);

  static _nop(e) => e;
  static bool _isNonZero(int n) => (n != 0);
  static int _returnZero() => 0;
  static int _defaultComparator(a, b) => Comparable.compare(a, b);
  static int _reverseComparator(a, b) => _defaultComparator(b, a);

  static int _compareLists(List a, List b, List<Comparator> comparators) {
    return new Iterable.generate(a.length, (i) => comparators[i](a[i], b[i]))
        .firstWhere(_isNonZero, orElse: _returnZero);
  }

  static List _sorted(
      List items, List<Mapper> mappers, List<Comparator> comparators, bool descending) {
    // Do the standard decorate-sort-undecorate aka Schwartzian dance since Dart
    // doesn't support a key/transform parameter to sort().
    // Ref: http://en.wikipedia.org/wiki/Schwartzian_transform
    mapper(e) => mappers.map((m) => m(e)).toList(growable: false);
    List decorated = items.map(mapper).toList(growable: false);
    List<int> indices = new Iterable.generate(decorated.length, _nop).toList(growable: false);
    comparator(i, j) => _compareLists(decorated[i], decorated[j], comparators);
    indices.sort((descending) ? (i, j) => comparator(j, i) : comparator);
    return indices.map((i) => items[i]).toList(growable: false);
  }

  /**
   * expression: String/Function or Array of String/Function.
   */
  List call(List items, var expression, [bool descending=false]) {
    List expressions = null;
    if (expression is String || expression is Mapper) {
      expressions = [expression];
    } else if (expression is List) {
      expressions = expression as List;
    }
    if (expressions == null || expressions.length == 0) {
      // AngularJS behavior.  You must have an expression to get any work done.
      return items;
    }
    int numExpressions = expressions.length;
    List<Mapper> mappers = new List(numExpressions);
    List<Comparator> comparators = new List<Comparator>(numExpressions);
    for (int i = 0; i < numExpressions; i++) {
      expression = expressions[i];
      if (expression is String) {
        var strExp = expression as String;
        var desc = false;
        if (strExp.startsWith('-') || strExp.startsWith('+')) {
          desc = strExp.startsWith('-');
          strExp = strExp.substring(1);
        }
        comparators[i] = desc ? _reverseComparator : _defaultComparator;
        if (strExp == '') {
          mappers[i] = _nop;
        } else {
          var parsed = _parser(strExp);
          mappers[i] = (e) => parsed.eval(e, null);
        }
      } else if (expression is Mapper) {
        mappers[i] = (expression as Mapper);
        comparators[i] = _defaultComparator;
      }
    }
    return _sorted(items, mappers, comparators, descending);
  }
}
part of angular.core.dom;

/**
 * Callback function used to notify of attribute changes.
 */
typedef AttributeChanged(String newValue);

/**
 * Callback function used to notify of text changes.
 */
abstract class TextChangeListener{
  call(String text);
}


/**
 * NodeAttrs is a facade for element attributes. The facade is responsible
 * for normalizing attribute names as well as allowing access to the
 * value of the directive.
 */
class NodeAttrs {
  final dom.Element element;

  Map<String, List<AttributeChanged>> _observers;

  NodeAttrs(dom.Element this.element);

  operator [](String name) => element.attributes[_snakeCase(name, '-')];

  operator []=(String name, String value) {
    name = _snakeCase(name, '-');
    if (value == null) {
      element.attributes.remove(name);
    } else {
      element.attributes[name] = value;
    }
    if (_observers != null && _observers.containsKey(name)) {
      _observers[name].forEach((fn) => fn(value));
    }
  }

  /**
   * Observe changes to the attribute by invoking the [AttributeChanged]
   * function. On registration the [AttributeChanged] function gets invoked
   * synchronise with the current value.
   */
  observe(String attributeName, AttributeChanged notifyFn) {
    attributeName = _snakeCase(attributeName, '-');
    if (_observers == null) {
      _observers = new Map<String, List<AttributeChanged>>();
    }
    if (!_observers.containsKey(attributeName)) {
      _observers[attributeName] = new List<AttributeChanged>();
    }
    _observers[attributeName].add(notifyFn);
    notifyFn(this[attributeName]);
  }
}

/**
 * TemplateLoader is an asynchronous access to ShadowRoot which is
 * loaded asynchronously. It allows a Component to be notified when its
 * ShadowRoot is ready.
 */
class TemplateLoader {
  final async.Future<dom.ShadowRoot> _template;

  async.Future<dom.ShadowRoot> get template => _template;

  TemplateLoader(this._template);
}

var _SNAKE_CASE_REGEXP = new RegExp("[A-Z]");
String _snakeCase(String name, [separator = '_']) {
  _snakeReplace(Match match) {
    return (match.start != 0 ? separator : '') + match.group(0).toLowerCase();
  }
  var x=  name.replaceAllMapped(_SNAKE_CASE_REGEXP, _snakeReplace);
  if (x is String) return x;
  throw [];
  return x;
}


part of angular.directive;

/**
 * Causes the compiler to ignore all Angular directives and markup on descendant
 * nodes of the matching element.  Note, however, that other directives and
 * markup on the element are still processed and that only descending the DOM
 * for compilation is prevented.
 *
 * Example:
 *
 *     <div foo="{{a}}" ng-non-bindable>
 *       <span ng-bind="b"></span>{{b}}
 *     </div>
 *
 * In the above example, because the `div` element has the `ng-non-bindable`
 * attribute set on it, the `ng-bind` directive and the interpolation for
 * `{{b}}` are not processed because Angular will not process the `span` child
 * element.  However, the `foo` attribute *will* be interpolated because it is
 * not on a child node. 
 */
@NgDirective(selector: '[ng-non-bindable]',
             children: NgAnnotation.IGNORE_CHILDREN)
class NgNonBindableDirective {}
part of angular.mock;

/**
 * A convenient way to assert the order in which the DOM elements are processed.
 *
 * In your test create:
 *
 *     <div log="foo">...</div>
 *
 * And then assert:
 *
 *     expect(logger).toEqual(['foo']);
 */
@NgDirective(
    selector: '[log]',
    map: const {
        'log': '@.logMessage'
    }
)
class LogAttrDirective implements NgAttachAware {
  final Logger log;
  String logMessage;
  LogAttrDirective(Logger this.log);
  attach() => log(logMessage == '' ? 'LOG' : logMessage);
}

/**
 * A convenient way to verify that a set of operations executed in a specific
 * order. Simply inject the Logger into each operation and call:
 *
 *     operation1(Logger logger) => logger('foo');
 *     operation2(Logger logger) => logger('bar');
 *
 *  Then in the test:
 *
 *     expect(logger).toEqual(['foo', 'bar']);
 */
class Logger implements List {
  final List tokens = [];

  /**
   * Add string token to the list.
   */
  call(dynamic text) => tokens.add(text);

  /**
   * Return a `;` separated list of recorded tokens.
   */
  String result() => tokens.join('; ');

  noSuchMethod(Invocation invocation) => mirror.reflect(tokens).delegate(invocation);
}
library angular.tools.common;

class DirectiveInfo {
  String selector;
  List<String> expressionAttrs = <String>[];
  List<String> expressions = <String>[];
  DirectiveInfo([this.selector, this.expressionAttrs, this.expressions]) {
    if (expressionAttrs == null) {
      expressionAttrs = <String>[];
    }
    if (expressions == null) {
      expressions = <String>[];
    }
  }
}

const String DIRECTIVE = 'DIRECTIVE';
const String COMPONENT = 'COMPONENT';

class DirectiveMetadata {
  String className;
  String type; // DIRECTIVE/COMPONENT
  String selector;
  Map<String, String> attributeMappings;
  List<String> exportExpressionAttrs;
  List<String> exportExpressions;

  DirectiveMetadata([this.className, this.type, this.selector,
                     this.attributeMappings, this.exportExpressionAttrs,
                     this.exportExpressions]) {
    if (attributeMappings == null) {
      attributeMappings = <String, String>{};
    }
    if (exportExpressions == null) {
      exportExpressions = <String>[];
    }
    if (exportExpressionAttrs == null) {
      exportExpressionAttrs = <String>[];
    }
  }
}

part of angular.mock;

List<Function> _asyncQueue = [];
List<_TimerSpec> _timerQueue = [];
List _asyncErrors = [];
bool _noMoreAsync = false;

/**
 * Runs any queued up async calls and any async calls queued with
 * running microLeap. Example:
 *
 *     it('should run async code', async(() {
 *       var thenRan = false;
 *       new Future.value('s').then((_) { thenRan = true; });
 *       expect(thenRan).toBe(false);
 *       microLeap();
 *       expect(thenRan).toBe(true);
 *     }));
 *
 *     it('should run chained thens', async(() {
 *       var log = [];
 *       new Future.value('s')
 *         .then((_) { log.add('firstThen'); })
 *         .then((_) { log.add('2ndThen'); });
 *       expect(log.join(' ')).toEqual('');
 *       microLeap();
 *       expect(log.join(' ')).toEqual('firstThen 2ndThen');
 *     }));
 *
 */
microLeap() {
  while (!_asyncQueue.isEmpty) {
    // copy the queue as it may change.
    var toRun = new List.from(_asyncQueue);
    _asyncQueue = [];
    // TODO: Support the case where multiple exceptions are thrown.
    // e.g. with a throwNextException() method.
    assert(_asyncErrors.isEmpty);
    toRun.forEach((fn) => fn());
    if (!_asyncErrors.isEmpty) {
      var e = _asyncErrors.removeAt(0);
      throw ['Async error', e, dartAsync.getAttachedStackTrace(e)];
    }
  }
}

/**
 * Simulates a clock tick by running any scheduled timers. Can only be used
 * in [async] tests.Clock tick will call [microLeap] to process the microtask
 * queue before each timer callback.
 *
 * Note: microtasks scheduled form the last timer are not going to be processed.
 *
 * Example:
 *
 *     it('should run queued timer after sufficient clock ticks', async(() {
 *       bool timerRan = false;
 *       new Timer(new Duration(milliseconds: 10), () => timerRan = true);
 *
 *       clockTick(milliseconds: 9);
 *       expect(timerRan).toBeFalsy();
 *       clockTick(milliseconds: 1);
 *       expect(timerRan).toBeTruthy();
 *     }));
 *
 *     it('should run periodic timer', async(() {
 *       int timerRan = 0;
 *       new Timer.periodic(new Duration(milliseconds: 10), (_) => timerRan++);
 *
 *       clockTick(milliseconds: 9);
 *       expect(timerRan).toBe(0);
 *       clockTick(milliseconds: 1);
 *       expect(timerRan).toBe(1);
 *       clockTick(milliseconds: 30);
 *       expect(timerRan).toBe(4);
 *     }));
 */
clockTick({int days: 0,
    int hours: 0,
    int minutes: 0,
    int seconds: 0,
    int milliseconds: 0,
    int microseconds: 0}) {
  var tickDuration = new Duration(days: days, hours: hours, minutes: minutes,
      seconds: seconds, milliseconds: milliseconds, microseconds: microseconds);

  var queue = _timerQueue;
  var remainingTimers = [];
  _timerQueue = [];
  queue.forEach((_TimerSpec spec) {
    if (!spec.isActive) return; // Skip over inactive timers.
    if (spec.periodic) {
      // We always add back the periodic timer unless it's cancelled.
      remainingTimers.add(spec);

      // Ignore ZERO duration ticks for periodic timers.
      if (tickDuration == Duration.ZERO) return;

      spec.elapsed += tickDuration;
      // Run the timer as many times as the timer priod fits into the tick.
      while (spec.elapsed >= spec.duration) {
        spec.elapsed -= spec.duration;
        microLeap();
        spec.fn(spec);
      }
    } else {
      spec.duration -= tickDuration;
      if (spec.duration <= Duration.ZERO) {
        microLeap();
        spec.fn();
      } else {
        remainingTimers.add(spec);
      }
    }
  });
  // Remaining timers should come before anything else scheduled after them.
  _timerQueue.insertAll(0, remainingTimers);
}

/**
* Causes runAsync calls to throw exceptions.
*
* This function is useful while debugging async tests: the exception
* is thrown from the runAsync call-site instead later in the test.
*/
noMoreAsync() {
  _noMoreAsync = true;
}

/**
* Captures all runAsync calls inside of a function.
*
* Typically used within a test: it('should be async', async(() { ... }));
*/
async(Function fn) =>
    () {
  _noMoreAsync = false;
  _asyncErrors = [];
  _timerQueue = [];
  var zoneSpec = new dartAsync.ZoneSpecification(
      scheduleMicrotask: (_, __, ___, asyncFn) {
        if (_noMoreAsync) {
          throw ['runAsync called after noMoreAsync()'];
        } else {
          _asyncQueue.add(asyncFn);
        }
      },
      createTimer: (_, __, ____, Duration duration, void f()) =>
          _createTimer(f, duration, false),
      createPeriodicTimer:
          (_, __, ___, Duration period, void f(dartAsync.Timer timer)) =>
              _createTimer(f, period, true),
      handleUncaughtError: (_, __, ___, e) => _asyncErrors.add(e)
  );
  dartAsync.runZoned(() {
      fn();
      microLeap();
    }, zoneSpecification: zoneSpec);

  _asyncErrors.forEach((e) {
    throw "During runZoned: $e.  Stack:\n${dartAsync.getAttachedStackTrace(e)}";
  });

  if (!_timerQueue.isEmpty && _timerQueue.any((_TimerSpec spec) => spec.isActive)) {
    throw ["${_timerQueue.where((_TimerSpec spec) => spec.isActive).length} "
           "active timer(s) are still in the queue."];
  }
};

_createTimer(Function fn, Duration duration, bool periodic) {
  var timer = new _TimerSpec(fn, duration, periodic);
  _timerQueue.add(timer);
  return timer;
}

/**
 * Enforces synchronous code.  Any calls to runAsync inside of 'sync'
 * will throw an exception.
 */
sync(Function fn) => () {
  dartAsync.runZoned(fn, zoneSpecification: new dartAsync.ZoneSpecification(
    scheduleMicrotask: (_, __, ___, asyncFn) =>
        throw ['runAsync called from sync function.'],
    createTimer: (_, __, ____, Duration duration, void f()) =>
        throw ['Timer created from sync function.'],
    createPeriodicTimer:
        (_, __, ___, Duration period, void f(dartAsync.Timer timer)) =>
            throw ['periodic Timer created from sync function.']
    ));
};

class _TimerSpec implements dartAsync.Timer {
  Function fn;
  Duration duration;
  Duration elapsed = Duration.ZERO;
  bool periodic;
  bool isActive = true;

  _TimerSpec(this.fn, this.duration, this.periodic);

  void cancel() {
    isActive = false;
  }
}
library angular.core.dom;

import 'dart:async' as async;
import 'dart:json' as json;
import 'dart:html' as dom;
import 'dart:mirrors';

import 'package:di/di.dart';
import 'package:perf_api/perf_api.dart';

import '../core/module.dart';
import '../core/parser/parser_library.dart';

part 'block.dart';
part 'block_factory.dart';
part 'common.dart';
part 'compiler.dart';
part 'directive.dart';
part 'http.dart';
part 'ng_mustache.dart';
part 'node_cursor.dart';
part 'selector.dart';
part 'template_cache.dart';
part 'tree_sanitizer.dart';

class NgCoreDomModule extends Module {
  NgCoreDomModule() {
    value(TextChangeListener, null);
    factory(TemplateCache, (_) => new TemplateCache(capacity: 0));
    type(dom.NodeTreeSanitizer, implementedBy: NullTreeSanitizer);

    type(NgTextMustacheDirective);
    type(NgAttrMustacheDirective);

    type(Compiler);
    type(Http);
    type(UrlRewriter);
    factory(HttpBackend, (i) { throw "Why not Override????"; });
    type(HttpDefaultHeaders);
    type(HttpDefaults);
    type(HttpInterceptors);
    type(BlockCache);
    type(GetterSetter);

  }
}
library selector;

import 'package:html5lib/dom.dart';

class ContainsSelector {
  String selector;
  RegExp regexp;

  ContainsSelector(this.selector, regexp) {
    this.regexp = new RegExp(regexp);
  }
}

RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|(?:\[([\w\-]+)(?:=([^\]]*))?\]))');
RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$');
RegExp _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); //
RegExp _ATTR_CONTAINS_REGEXP = new RegExp(r'^\[\*=\/(.+)\/\]$'); //

class _SelectorPart {
  final String element;
  final String className;
  final String attrName;
  final String attrValue;

  const _SelectorPart.fromElement(String this.element)
      : className = null, attrName = null, attrValue = null;

  const _SelectorPart.fromClass(String this.className)
      : element = null, attrName = null, attrValue = null;


  const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue)
      : element = null, className = null;

  toString() =>
    element == null
      ? (className == null
         ? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]')
         : '.$className')
      : element;
}

List<_SelectorPart> _splitCss(String selector) {
  List<_SelectorPart> parts = [];
  var remainder = selector;
  var match;
  while (!remainder.isEmpty) {
    if ((match = _SELECTOR_REGEXP.firstMatch(remainder)) != null) {
      if (match[1] != null) {
        parts.add(new _SelectorPart.fromElement(match[1].toLowerCase()));
      } else if (match[2] != null) {
        parts.add(new _SelectorPart.fromClass(match[2].toLowerCase()));
      } else if (match[3] != null) {
        var attrValue = match[4] == null ? '' : match[4].toLowerCase();
        parts.add(new _SelectorPart.fromAttribute(match[3].toLowerCase(),
                                                  attrValue));
      } else {
        throw "Missmatched RegExp $_SELECTOR_REGEXP on $remainder";
      }
    } else {
      throw "Unknown selector format '$remainder'.";
    }
    remainder = remainder.substring(match.end);
  }
  return parts;
}

bool matchesNode(Node node, String selector) {
  var match, selectorParts;
  if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
    if (node is! Text) {
      return false;
    }
    return new RegExp(match.group(1)).hasMatch((node as Text).value);
  } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
    if (node is! Element) {
      return false;
    }
    var regexp = new RegExp(match.group(1));
    for (String attrName in node.attributes.keys) {
      if (regexp.hasMatch(node.attributes[attrName])) {
        return true;
      }
    }
    return false;
  } else if ((selectorParts = _splitCss(selector)) != null) {
    if (node is! Element) {
      return false;
    }
    String nodeName = node.tagName.toLowerCase();

    bool stillGood = true;
    selectorParts.forEach((_SelectorPart part) {
      if (part.element != null) {
        if (nodeName != part.element) {
          stillGood = false;
        }
      } else if (part.className != null) {
        if (node.attributes['class'] == null ||
            !node.attributes['class'].split(' ').contains(part.className)) {
          stillGood = false;
        }
      } else if (part.attrName != null) {
        if (part.attrValue == '' ?
              node.attributes[part.attrName] == null :
              node.attributes[part.attrName] != part.attrValue) {
          stillGood = false;
        }
      }
    });

    return stillGood;
  } else {
    throw new ArgumentError('Unsupported Selector: $selector');
  }

  switch(node.nodeType) {
    case 1: // Element
      break;
    case 3: // Text Node
      break;
  }
  return false;
}
// 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.

part of intl;

/**
 * This is a private class internal to DateFormat which is used for formatting
 * particular fields in a template. e.g. if the format is hh:mm:ss then the
 * fields would be "hh", ":", "mm", ":", and "ss". Each type of field knows
 * how to format that portion of a date.
 */
abstract class _DateFormatField {
  /** The format string that defines us, e.g. "hh" */
  String pattern;

  /** The DateFormat that we are part of.*/
  DateFormat parent;

  _DateFormatField(this.pattern, this.parent);

  /**
   * Return the width of [pattern]. Different widths represent different
   * formatting options. See the comment for DateFormat for details.
   */
  int get width => pattern.length;

  String fullPattern() => pattern;

  String toString() => pattern;

  /** Format date according to our specification and return the result. */
  String format(DateTime date) {
    // Default implementation in the superclass, works for both types of
    // literal patterns, and is overridden by _DateFormatPatternField.
    return pattern;
  }

  /** Abstract method for subclasses to implementing parsing for their format.*/
  void parse(_Stream input, _DateBuilder dateFields);

  /** Parse a literal field. We just look for the exact input. */
  void parseLiteral(_Stream input) {
    var found = input.read(width);
    if (found != pattern) {
      throwFormatException(input);
    }
  }

  /** Throw a format exception with an error message indicating the position.*/
  void throwFormatException(_Stream stream) {
    throw new FormatException("Trying to read $this from ${stream.contents} "
        "at position ${stream.index}");
  }
}

/**
 * Represents a literal field - a sequence of characters that doesn't
 * change according to the date's data. As such, the implementation
 * is extremely simple.
 */
class _DateFormatLiteralField extends _DateFormatField {

  _DateFormatLiteralField(pattern, parent): super(pattern, parent);

  parse(_Stream input, _DateBuilder dateFields) {
    return parseLiteral(input);
  }
}

/**
 * Represents a literal field with quoted characters in it. This is
 * only slightly more complex than a _DateFormatLiteralField.
 */
class _DateFormatQuotedField extends _DateFormatField {

  String _fullPattern;

  String fullPattern() => _fullPattern;

  _DateFormatQuotedField(pattern, parent): super(pattern, parent) {
    _fullPattern = pattern;
    patchQuotes();
  }

  parse(_Stream input, _DateBuilder dateFields) {
    return parseLiteral(input);
  }

  void patchQuotes() {
     if (pattern == "''") {
      pattern = "'";
    } else {
      pattern = pattern.substring(1, pattern.length - 1);
      var twoEscapedQuotes = new RegExp(r"''");
      pattern = pattern.replaceAll(twoEscapedQuotes, "'");
    }
  }
}

/*
 * Represents a field in the pattern that formats some aspect of the
 * date. Consists primarily of a switch on the particular pattern characters
 * to determine what to do.
 */
class _DateFormatPatternField extends _DateFormatField {

  _DateFormatPatternField(pattern, parent): super(pattern,  parent);

  /** Format date according to our specification and return the result. */
  String format(DateTime date) {
      return formatField(date);
  }

  /**
   * Parse the date according to our specification and put the result
   * into the correct place in dateFields.
   */
  void parse(_Stream input, _DateBuilder dateFields) {
    parseField(input, dateFields);
  }

  /**
   * Parse a field representing part of a date pattern. Note that we do not
   * return a value, but rather build up the result in [builder].
   */
  void parseField(_Stream input, _DateBuilder builder) {
   try {
     switch(pattern[0]) {
       case 'a': parseAmPm(input, builder); break;
       case 'c': parseStandaloneDay(input); break;
       case 'd': handleNumericField(input, builder.setDay); break; // day
       // Day of year. Setting month=January with any day of the year works
       case 'D': handleNumericField(input, builder.setDay); break; // dayofyear
       case 'E': parseDayOfWeek(input); break;
       case 'G': break; // era
       case 'h': parse1To12Hours(input, builder); break;
       case 'H': handleNumericField(input, builder.setHour); break; // hour 0-23
       case 'K': handleNumericField(input, builder.setHour); break; //hour 0-11
       case 'k': handleNumericField(input, builder.setHour,-1); break; //hr 1-24
       case 'L': parseStandaloneMonth(input, builder); break;
       case 'M': parseMonth(input, builder); break;
       case 'm': handleNumericField(input, builder.setMinute); break; // minutes
       case 'Q': break; // quarter
       case 'S': handleNumericField(input, builder.setFractionalSecond); break;
       case 's': handleNumericField(input, builder.setSecond); break;
       case 'v': break; // time zone id
       case 'y': handleNumericField(input, builder.setYear); break;
       case 'z': break; // time zone
       case 'Z': break; // time zone RFC
       default: return;
     }
   } catch (e) { throwFormatException(input); }
 }

  /** Formatting logic if we are of type FIELD */
  String formatField(DateTime date) {
     switch (pattern[0]) {
      case 'a': return formatAmPm(date);
      case 'c': return formatStandaloneDay(date);
      case 'd': return formatDayOfMonth(date);
      case 'D': return formatDayOfYear(date);
      case 'E': return formatDayOfWeek(date);
      case 'G': return formatEra(date);
      case 'h': return format1To12Hours(date);
      case 'H': return format0To23Hours(date);
      case 'K': return format0To11Hours(date);
      case 'k': return format24Hours(date);
      case 'L': return formatStandaloneMonth(date);
      case 'M': return formatMonth(date);
      case 'm': return formatMinutes(date);
      case 'Q': return formatQuarter(date);
      case 'S': return formatFractionalSeconds(date);
      case 's': return formatSeconds(date);
      case 'v': return formatTimeZoneId(date);
      case 'y': return formatYear(date);
      case 'z': return formatTimeZone(date);
      case 'Z': return formatTimeZoneRFC(date);
      default: return '';
    }
  }

  /** Return the symbols for our current locale. */
  DateSymbols get symbols => dateTimeSymbols[parent.locale];

  formatEra(DateTime date) {
    var era = date.year > 0 ? 1 : 0;
    return width >= 4 ? symbols.ERANAMES[era] :
                        symbols.ERAS[era];
  }

  formatYear(DateTime date) {
    // TODO(alanknight): Proper handling of years <= 0
    var year = date.year;
    if (year < 0) {
      year = -year;
    }
    return width == 2 ? padTo(2, year % 100) : year.toString();
  }

  /**
   * We are given [input] as a stream from which we want to read a date. We
   * can't dynamically build up a date, so we are given a list [dateFields] of
   * the constructor arguments and an [position] at which to set it
   * (year,month,day,hour,minute,second,fractionalSecond)
   * then after all parsing is done we construct a date from the arguments.
   * This method handles reading any of the numeric fields. The [offset]
   * argument allows us to compensate for zero-based versus one-based values.
   */
  void handleNumericField(_Stream input, Function setter, [int offset = 0]) {
    var result = input.nextInteger();
    if (result == null) throwFormatException(input);
    setter(result + offset);
  }

  /**
   * We are given [input] as a stream from which we want to read a date. We
   * can't dynamically build up a date, so we are given a list [dateFields] of
   * the constructor arguments and an [position] at which to set it
   * (year,month,day,hour,minute,second,fractionalSecond)
   * then after all parsing is done we construct a date from the arguments.
   * This method handles reading any of string fields from an enumerated set.
   */
   int parseEnumeratedString(_Stream input, List possibilities) {
     var results = new _Stream(possibilities).findIndexes(
       (each) => input.peek(each.length) == each);
     if (results.isEmpty) throwFormatException(input);
     results.sort(
       (a, b) => possibilities[a].length.compareTo(possibilities[b].length));
     var longestResult = results.last;
     input.read(possibilities[longestResult].length);
     return longestResult;
     }

  String formatMonth(DateTime date) {
    switch (width) {
      case 5: return symbols.NARROWMONTHS[date.month-1];
      case 4: return symbols.MONTHS[date.month-1];
      case 3: return symbols.SHORTMONTHS[date.month-1];
      default:
        return padTo(width, date.month);
    }
  }

  void parseMonth(input, dateFields) {
    var possibilities;
    switch(width) {
      case 5: possibilities = symbols.NARROWMONTHS; break;
      case 4: possibilities = symbols.MONTHS; break;
      case 3: possibilities = symbols.SHORTMONTHS; break;
      default: return handleNumericField(input, dateFields.setMonth);
    }
    dateFields.month = parseEnumeratedString(input, possibilities) + 1;
  }

  String format24Hours(DateTime date) {
    return padTo(width, date.hour);
  }

  String formatFractionalSeconds(DateTime date) {
    // Always print at least 3 digits. If the width is greater, append 0s
    var basic = padTo(3, date.millisecond);
    if (width - 3 > 0) {
      var extra = padTo(width - 3, 0);
      return basic + extra;
    } else {
      return basic;
    }
  }

  String formatAmPm(DateTime date) {
    var hours = date.hour;
    var index = (date.hour >= 12) && (date.hour < 24) ? 1 : 0;
    var ampm = symbols.AMPMS;
    return ampm[index];
  }

  void parseAmPm(input, dateFields) {
    // If we see a "PM" note it in an extra field.
    var ampm = parseEnumeratedString(input, symbols.AMPMS);
    if (ampm == 1) dateFields.pm = true;
  }

  String format1To12Hours(DateTime date) {
    var hours = date.hour;
    if (date.hour > 12) hours = hours - 12;
    if (hours == 0) hours = 12;
    return padTo(width, hours);
  }

  void parse1To12Hours(_Stream input, _DateBuilder dateFields) {
    handleNumericField(input, dateFields.setHour);
    if (dateFields.hour == 12) dateFields.hour = 0;
  }

  String format0To11Hours(DateTime date) {
    return padTo(width, date.hour % 12);
  }

  String format0To23Hours(DateTime date) {
    return padTo(width, date.hour);
  }

  String formatStandaloneDay(DateTime date) {
    switch (width) {
      case 5: return symbols.STANDALONENARROWWEEKDAYS[date.weekday % 7];
      case 4: return symbols.STANDALONEWEEKDAYS[date.weekday % 7];
      case 3: return symbols.STANDALONESHORTWEEKDAYS[date.weekday % 7];
      default:
        return padTo(1, date.day);
    }
  }

  void parseStandaloneDay(_Stream input) {
    // This is ignored, but we still have to skip over it the correct amount.
    var possibilities;
    switch(width) {
      case 5: possibilities = symbols.STANDALONENARROWWEEKDAYS; break;
      case 4: possibilities = symbols.STANDALONEWEEKDAYS; break;
      case 3: possibilities = symbols.STANDALONESHORTWEEKDAYS; break;
      default: return handleNumericField(input, (x)=>x);
    }
    parseEnumeratedString(input, possibilities);
  }

  String formatStandaloneMonth(DateTime date) {
  switch (width) {
    case 5:
      return symbols.STANDALONENARROWMONTHS[date.month-1];
    case 4:
      return symbols.STANDALONEMONTHS[date.month-1];
    case 3:
      return symbols.STANDALONESHORTMONTHS[date.month-1];
    default:
      return padTo(width, date.month);
    }
  }

  void parseStandaloneMonth(input, dateFields) {
    var possibilities;
    switch(width) {
      case 5: possibilities = symbols.STANDALONENARROWMONTHS; break;
      case 4: possibilities = symbols.STANDALONEMONTHS; break;
      case 3: possibilities = symbols.STANDALONESHORTMONTHS; break;
      default: return handleNumericField(input, dateFields.setMonth);
    }
    dateFields.month = parseEnumeratedString(input, possibilities) + 1;
  }

  String formatQuarter(DateTime date) {
    var quarter = ((date.month - 1) / 3).truncate();
    if (width < 4) {
      return symbols.SHORTQUARTERS[quarter];
    } else {
      return symbols.QUARTERS[quarter];
    }
  }
  String formatDayOfMonth(DateTime date) {
    return padTo(width, date.day);
  }

  String formatDayOfYear(DateTime date) => padTo(width, dayNumberInYear(date));

  /** Return the ordinal day, i.e. the day number in the year. */
  int dayNumberInYear(DateTime date) {
    if (date.month == 1) return date.day;
    if (date.month == 2) return date.day + 31;
    return ordinalDayFromMarchFirst(date) + 59 + (isLeapYear(date) ? 1 : 0);
  }

  /**
   * Return the day of the year counting March 1st as 1, after which the
   * number of days per month is constant, so it's easier to calculate.
   * Formula from http://en.wikipedia.org/wiki/Ordinal_date
   */
  int ordinalDayFromMarchFirst(DateTime date) =>
      ((30.6 * date.month) - 91.4).floor() + date.day;

  /**
   * Return true if this is a leap year. Rely on [DateTime] to do the
   * underlying calculation, even though it doesn't expose the test to us.
   */
  bool isLeapYear(DateTime date) {
    var feb29 = new DateTime(date.year, 2, 29);
    return feb29.month == 2;
  }

  String formatDayOfWeek(DateTime date) {
    // Note that Dart's weekday returns 1 for Monday and 7 for Sunday.
    return (width >= 4 ? symbols.WEEKDAYS :
                        symbols.SHORTWEEKDAYS)[(date.weekday) % 7];
  }

  void parseDayOfWeek(_Stream input) {
    // This is IGNORED, but we still have to skip over it the correct amount.
    var possibilities = width >= 4 ? symbols.WEEKDAYS : symbols.SHORTWEEKDAYS;
    parseEnumeratedString(input, possibilities);
  }

  String formatMinutes(DateTime date) {
    return padTo(width, date.minute);
  }

  String formatSeconds(DateTime date) {
    return padTo(width, date.second);
  }

  String formatTimeZoneId(DateTime date) {
    // TODO(alanknight): implement time zone support
    throw new UnimplementedError();
  }

  String formatTimeZone(DateTime date) {
    throw new UnimplementedError();
  }

  String formatTimeZoneRFC(DateTime date) {
    throw new UnimplementedError();
  }

 /**
  * Return a string representation of the object padded to the left with
  * zeros. Primarily useful for numbers.
  */
  String padTo(int width, Object toBePrinted) {
    var basicString = toBePrinted.toString();
    if (basicString.length >= width) return basicString;
    var buffer = new StringBuffer();
    for (var i = 0; i < width - basicString.length; i++) {
      buffer.write('0');
     }
    buffer.write(basicString);
    return buffer.toString();
  }
}
library source_crawler;

import 'package:analyzer_experimental/src/generated/ast.dart';

typedef CompilationUnitVisitor(CompilationUnit cu);

/**
 * Dart source file crawler. As it crawls Dart source, it calls
 * [CompilationUnitVisitor] on each file.
 */
abstract class SourceCrawler {
  void crawl(String entryPoint, CompilationUnitVisitor visitor);
}
// 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.


part of intl;

/**
 * A class for holding onto the data for a date so that it can be built
 * up incrementally.
 */
class _DateBuilder {
  // Default the date values to the EPOCH so that there's a valid date
  // in case the format doesn't set them.
  int year = 1970,
      month = 1,
      day = 1,
      hour = 0,
      minute = 0,
      second = 0,
      fractionalSecond = 0;
  bool pm = false;
  bool utc = false;

  // Functions that exist just to be closurized so we can pass them to a general
  // method.
  void setYear(x) { year = x; }
  void setMonth(x) { month = x; }
  void setDay(x) { day = x; }
  void setHour(x) { hour = x; }
  void setMinute(x) { minute = x; }
  void setSecond(x) { second = x; }
  void setFractionalSecond(x) { fractionalSecond = x; }

  /**
   * Return a date built using our values. If no date portion is set,
   * use the "Epoch" of January 1, 1970.
   */
  DateTime asDate() {
    // TODO(alanknight): Validate the date, especially for things which
    // can crash the VM, e.g. large month values.
    if (utc) {
      return new DateTime.utc(
          year,
          month,
          day,
          pm ? hour + 12 : hour,
          minute,
          second,
          fractionalSecond);
    } else {
      return new DateTime(
          year,
          month,
          day,
          pm ? hour + 12 : hour,
          minute,
          second,
          fractionalSecond);
    }
  }
}

/**
 * A simple and not particularly general stream class to make parsing
 * dates from strings simpler. It is general enough to operate on either
 * lists or strings.
 */
class _Stream {
  var contents;
  int index = 0;

  _Stream(this.contents);

  bool atEnd() => index >= contents.length;

  next() => contents[index++];

  /**
   * Return the next [howMany] items, or as many as there are remaining.
   * Advance the stream by that many positions.
   */
  read([howMany = 1]) {
    var result = peek(howMany);
    index += howMany;
    return result;
  }

  /**
   * Return the next [howMany] items, or as many as there are remaining.
   * Does not modify the stream position.
   */
  peek([howMany = 1]) {
    var result;
    if (contents is String) {
      result = contents.substring(
          index,
          min(index + howMany, contents.length));
    } else {
      // Assume List
      result = contents.sublist(index, index + howMany);
    }
    return result;
  }

  /** Return the remaining contents of the stream */
  rest() => peek(contents.length - index);

  /**
   * Find the index of the first element for which [f] returns true.
   * Advances the stream to that position.
   */
  int findIndex(Function f) {
    while (!atEnd()) {
      if (f(next())) return index - 1;
    }
    return null;
  }

  /**
   * Find the indexes of all the elements for which [f] returns true.
   * Leaves the stream positioned at the end.
   */
  List findIndexes(Function f) {
    var results = [];
    while (!atEnd()) {
      if (f(next())) results.add(index - 1);
    }
    return results;
  }

  /**
   * Assuming that the contents are characters, read as many digits as we
   * can see and then return the corresponding integer. Advance the stream.
   */
  var digitMatcher = new RegExp(r'\d+');
  int nextInteger() {
    var string = digitMatcher.stringMatch(rest());
    if (string == null || string.isEmpty) return null;
    read(string.length);
    return int.parse(string);
  }
}
library angular.source_crawler_impl;

import 'dart:io';
import 'package:analyzer_experimental/analyzer.dart';
import 'source_crawler.dart';

const String PACKAGE_PREFIX = 'package:';

/**
 * Dart source file crawler. As it crawls Dart source, it calls
 * [CompilationUnitVisitor] on each file.
 */
class SourceCrawlerImpl implements SourceCrawler {
  final List<String> packageRoots;

  SourceCrawlerImpl(this.packageRoots);

  void crawl(String entryPoint, CompilationUnitVisitor visitor) {
    List<String> visited = <String>[];
    List<String> toVisit = <String>[];
    if (entryPoint.startsWith(PACKAGE_PREFIX)) {
      var path = resolvePackagePath(entryPoint);
      if (path == null) {
        throw 'Unable to resolve $entryPoint';
      }
      toVisit.add(path);
    } else {
      toVisit.add(entryPoint);
    }

    while (toVisit.isNotEmpty) {
      var currentFile = toVisit.removeAt(0);
      visited.add(currentFile);
      var currentDir = new File(currentFile).directory.path;
      CompilationUnit cu = parseDartFile(currentFile);
      processImports(cu, currentDir, currentFile, visited, toVisit);
      visitor(cu);
    }
  }

  void processImports(CompilationUnit cu, String currentDir,
                      String currentFile, List<String> visited,
                      List<String> toVisit) {
    cu.directives.forEach((Directive directive) {
      if (directive is ImportDirective || directive is PartDirective) {
        UriBasedDirective import = directive;
        String canonicalFile = canonicalizeImportPath(
            currentDir, currentFile, import.uri.stringValue);
        if (canonicalFile == null) return;
        if (!visited.contains(canonicalFile) &&
            !toVisit.contains(canonicalFile)) {
          toVisit.add(canonicalFile);
        }
      }
    });
  }

  String canonicalizeImportPath(String currentDir,
                                String currentFile,
                                String uri) {
    // ignore core libraries
    if (uri.startsWith('dart:')) {
      return null;
    }
    if (uri.startsWith(PACKAGE_PREFIX)) {
      return resolvePackagePath(uri);
    }
    // relative import.
    if (uri.startsWith('../')) {
      while (uri.startsWith('../')) {
        uri = uri.substring('../'.length);
        currentDir = currentDir.substring(0, currentDir.lastIndexOf('/'));
      }
    }
    return '$currentDir/$uri';
  }

  String resolvePackagePath(String uri) {
    for (String packageRoot in packageRoots) {
      var resolvedPath = _packageUriResolver(uri, packageRoot);
      if (new File(resolvedPath).existsSync()) {
        return resolvedPath;
      }
    }
    return null;
  }

  String _packageUriResolver(String uri, String packageRoot) {
    var packagePath = uri.substring(PACKAGE_PREFIX.length);
    if (!packageRoot.endsWith('/')) {
      packageRoot = packageRoot + '/';
    }
    return packageRoot + packagePath;
  }
}
part of angular.mock;

/*
 * Use Probe directive to capture the Scope, Injector and Element from any DOM
 * location into root-scope. This is useful for testing to get a hold of
 * any directive.
 *
 *    <div some-directive probe="myProbe">..</div>
 *
 *    rootScope.myProbe.directive(SomeAttrDirective);
 */
@NgDirective(selector: '[probe]')
class Probe implements NgDetachAware {
  final Scope scope;
  final Injector injector;
  final Element element;
  final NodeAttrs _attrs;

  Probe(Scope this.scope, Injector this.injector, Element this.element, NodeAttrs this._attrs) {
    scope.$root[_attrs['probe']] = this;
  }

  detach() => scope.$root[_attrs['probe']] = null;

  /**
   * Retrieve a Directive at the current element.
   */
  directive(Type type) => injector.get(type);
}

// 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.

part of intl;

/**
 * Bidi stands for Bi-directional text.
 * According to http://en.wikipedia.org/wiki/Bi-directional_text:
 * Bi-directional text is text containing text in both text directionalities,
 * both right-to-left (RTL) and left-to-right (LTR). It generally involves text
 * containing different types of alphabets, but may also refer to boustrophedon,
 * which is changing text directionality in each row.
 *
 * This file provides some utility classes for determining directionality of
 * text, switching CSS layout from LTR to RTL, and other normalizing utilities
 * needed when switching between RTL and LTR formatting.
 *
 * It defines the TextDirection class which is used to represent directionality
 * of text,
 * In most cases, it is preferable to use bidi_formatter.dart, which provides
 * bidi functionality in the given directional context, instead of using
 * bidi_utils.dart directly.
 */
class TextDirection {
  static const LTR = const TextDirection._('LTR', 'ltr');
  static const RTL = const TextDirection._('RTL', 'rtl');
  // If the directionality of the text cannot be determined and we are not using
  // the context direction (or if the context direction is unknown), then the
  // text falls back on the more common ltr direction.
  static const UNKNOWN = const TextDirection._('UNKNOWN', 'ltr');

  /**
   * Textual representation of the directionality constant. One of
   * 'LTR', 'RTL', or 'UNKNOWN'.
   */
  final String value;

  /** Textual representation of the directionality when used in span tag. */
  final String spanText;

  const TextDirection._(this.value, this.spanText);

  /**
   * Returns true if [otherDirection] is known to be different from this
   * direction.
   */
  bool isDirectionChange(TextDirection otherDirection) {
    return otherDirection != TextDirection.UNKNOWN && this != otherDirection;
  }
}

/**
 * This provides utility methods for working with bidirectional text. All
 * of the methods are static, and are organized into a class primarily to
 * group them together for documentation and discoverability.
 */
class Bidi {

  /** Unicode "Left-To-Right Embedding" (LRE) character. */
  static const LRE = '\u202A';

  /** Unicode "Right-To-Left Embedding" (RLE) character. */
  static const RLE = '\u202B';

  /** Unicode "Pop Directional Formatting" (PDF) character. */
  static const PDF = '\u202C';

  /** Unicode "Left-To-Right Mark" (LRM) character. */
  static const LRM = '\u200E';

  /** Unicode "Right-To-Left Mark" (RLM) character. */
  static const RLM = '\u200F';

  /** Constant to define the threshold of RTL directionality. */
  static num _RTL_DETECTION_THRESHOLD = 0.40;

  /**
   * Practical patterns to identify strong LTR and RTL characters, respectively.
   * These patterns are not completely correct according to the Unicode
   * standard. They are simplified for performance and small code size.
   */
  static const String _LTR_CHARS =
      r'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590'
      r'\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF';
  static const String _RTL_CHARS = r'\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';

  /**
   * Returns the input [text] with spaces instead of HTML tags or HTML escapes,
   * which is helpful for text directionality estimation.
   * Note: This function should not be used in other contexts.
   * It does not deal well with many things: comments, script,
   * elements, style elements, dir attribute,`>` in quoted attribute values,
   * etc. But it does handle well enough the most common use cases.
   * Since the worst that can happen as a result of these shortcomings is that
   * the wrong directionality will be estimated, we have not invested in
   * improving this.
   */
  static String stripHtmlIfNeeded(String text) {
    // The regular expression is simplified for an HTML tag (opening or
    // closing) or an HTML escape. We might want to skip over such expressions
    // when estimating the text directionality.
    return text.replaceAll(new RegExp(r'<[^>]*>|&[^;]+;'), ' ');
  }

  /**
   * Determines if the first character in [text] with strong directionality is
   * LTR. If [isHtml] is true, the text is HTML or HTML-escaped.
   */
  static bool startsWithLtr(String text, [isHtml=false]) {
    return new RegExp('^[^$_RTL_CHARS]*[$_LTR_CHARS]').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Determines if the first character in [text] with strong directionality is
   * RTL. If [isHtml] is true, the text is HTML or HTML-escaped.
   */
  static bool startsWithRtl(String text, [isHtml=false]) {
    return new RegExp('^[^$_LTR_CHARS]*[$_RTL_CHARS]').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Determines if the exit directionality (ie, the last strongly-directional
   * character in [text] is LTR. If [isHtml] is true, the text is HTML or
   * HTML-escaped.
   */
  static bool endsWithLtr(String text, [isHtml=false]) {
    return new RegExp('[$_LTR_CHARS][^$_RTL_CHARS]*\$').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Determines if the exit directionality (ie, the last strongly-directional
   * character in [text] is RTL. If [isHtml] is true, the text is HTML or
   * HTML-escaped.
   */
  static bool endsWithRtl(String text, [isHtml=false]) {
    return new RegExp('[$_RTL_CHARS][^$_LTR_CHARS]*\$').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Determines if the given [text] has any LTR characters in it.
   * If [isHtml] is true, the text is HTML or HTML-escaped.
   */
  static bool hasAnyLtr(String text, [isHtml=false]) {
    return new RegExp(r'[' '$_LTR_CHARS' r']').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Determines if the given [text] has any RTL characters in it.
   * If [isHtml] is true, the text is HTML or HTML-escaped.
   */
  static bool hasAnyRtl(String text, [isHtml=false]) {
    return new RegExp(r'[' '$_RTL_CHARS' r']').hasMatch(
        isHtml? stripHtmlIfNeeded(text) : text);
  }

  /**
   * Check if a BCP 47 / III [languageString] indicates an RTL language.
   *
   * i.e. either:
   * - a language code explicitly specifying one of the right-to-left scripts,
   *   e.g. "az-Arab", or
   * - a language code specifying one of the languages normally written in a
   *   right-to-left script, e.g. "fa" (Farsi), except ones explicitly
   *   specifying Latin or Cyrillic script (which are the usual LTR
   *   alternatives).
   *
   * The list of right-to-left scripts appears in the 100-199 range in
   * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
   * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
   * Tifinagh, which also have significant modern usage. The rest (Syriac,
   * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
   * and are not recognized.
   * The languages usually written in a right-to-left script are taken as those
   * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng  in
   * http://www.iana.org/assignments/language-subtag-registry,
   * as well as Sindhi (sd) and Uyghur (ug).
   * The presence of other subtags of the language code, e.g. regions like EG
   * (Egypt), is ignored.
   */
  static bool isRtlLanguage(String languageString) {
    return new RegExp(r'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]'
        r'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))'
        r'($|-|_)', caseSensitive: false).hasMatch(languageString);
  }

  /**
   * Enforce the [html] snippet in RTL directionality regardless of overall
   * context. If the html piece was enclosed by a tag, the direction will be
   * applied to existing tag, otherwise a span tag will be added as wrapper.
   * For this reason, if html snippet start with with tag, this tag must enclose
   * the whole piece. If the tag already has a direction specified, this new one
   * will override existing one in behavior (should work on Chrome, FF, and IE
   * since this was ported directly from the Closure version).
   */
  static String enforceRtlInHtml(String html) {
    return _enforceInHtmlHelper(html, 'rtl');
  }

  /**
   * Enforce RTL on both end of the given [text] using unicode BiDi formatting
   * characters RLE and PDF.
   */
  static String enforceRtlInText(String text) {
    return '$RLE$text$PDF';
  }

  /**
   * Enforce the [html] snippet in LTR directionality regardless of overall
   * context. If the html piece was enclosed by a tag, the direction will be
   * applied to existing tag, otherwise a span tag will be added as wrapper.
   * For this reason, if html snippet start with with tag, this tag must enclose
   * the whole piece. If the tag already has a direction specified, this new one
   * will override existing one in behavior (tested on FF and IE).
   */
  static String enforceLtrInHtml(String html) {
    return _enforceInHtmlHelper(html, 'ltr');
  }

  /**
   * Enforce LTR on both end of the given [text] using unicode BiDi formatting
   * characters LRE and PDF.
   */
  static String enforceLtrInText(String text) {
    return '$LRE$text$PDF';
  }

  /**
   * Enforce the [html] snippet in the desired [direction] regardless of overall
   * context. If the html piece was enclosed by a tag, the direction will be
   * applied to existing tag, otherwise a span tag will be added as wrapper.
   * For this reason, if html snippet start with with tag, this tag must enclose
   * the whole piece. If the tag already has a direction specified, this new one
   * will override existing one in behavior (tested on FF and IE).
   */
  static String _enforceInHtmlHelper(String html, String direction) {
    if (html.startsWith('<')) {
      StringBuffer buffer = new StringBuffer();
      var startIndex = 0;
      Match match = new RegExp('<\\w+').firstMatch(html);
      if (match != null) {
        buffer..write(html.substring(startIndex, match.end))
              ..write(' dir=$direction');
        startIndex = match.end;
      }
      return (buffer..write(html.substring(startIndex))).toString();
    }
    // '\n' is important for FF so that it won't incorrectly merge span groups.
    return '\n<span dir=$direction>$html</span>';
  }

  /**
   * Apply bracket guard to [str] using html span tag. This is to address the
   * problem of messy bracket display that frequently happens in RTL layout.
   * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
   * directionality, regardless of the estimated directionality.
   */
  static String guardBracketInHtml(String str, [bool isRtlContext]) {
    var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
    RegExp matchingBrackets =
        new RegExp(r'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)');
    return _guardBracketHelper(str, matchingBrackets,
        '<span dir=${useRtl? "rtl" : "ltr"}>', '</span>');
  }

  /**
   * Apply bracket guard to [str] using LRM and RLM. This is to address the
   * problem of messy bracket display that frequently happens in RTL layout.
   * This version works for both plain text and html, but in some cases is not
   * as good as guardBracketInHtml.
   * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
   * directionality, regardless of the estimated directionality.
   */
  static String guardBracketInText(String str, [bool isRtlContext]) {
    var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
    var mark = useRtl ? RLM : LRM;
    return _guardBracketHelper(str,
        new RegExp(r'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)'), mark, mark);
  }

  /**
   * (Mostly) reimplements the $& functionality of "replace" in JavaScript.
   * Given a [str] and the [regexp] to match with, optionally supply a string to
   * be inserted [before] the match and/or [after]. For example,
   * `_guardBracketHelper('firetruck', new RegExp('truck'), 'hydrant', '!')`
   * would return 'firehydrant!'.
   */
  // TODO(efortuna): Get rid of this once this is implemented in Dart.
  // See Issue 2979.
  static String _guardBracketHelper(String str, RegExp regexp, [String before,
      String after]) {
    StringBuffer buffer = new StringBuffer();
    var startIndex = 0;
    Iterable matches = regexp.allMatches(str);
    for (Match match in matches) {
      buffer..write(str.substring(startIndex, match.start))
            ..write(before)
            ..write(str.substring(match.start, match.end))
            ..write(after);
      startIndex = match.end;
    }
    return (buffer..write(str.substring(startIndex))).toString();
  }

  /**
   * Estimates the directionality of [text] using the best known
   * general-purpose method (using relative word counts). A
   * TextDirection.UNKNOWN return value indicates completely neutral input.
   * [isHtml] is true if [text] HTML or HTML-escaped.
   *
   * If the number of RTL words is above a certain percentage of the total
   * number of strongly directional words, returns RTL.
   * Otherwise, if any words are strongly or weakly LTR, returns LTR.
   * Otherwise, returns UNKNOWN, which is used to mean `neutral`.
   * Numbers and URLs are counted as weakly LTR.
   */
  static TextDirection estimateDirectionOfText(String text,
                                               {bool isHtml: false}) {
    text = isHtml? stripHtmlIfNeeded(text) : text;
    var rtlCount = 0;
    var total = 0;
    var hasWeaklyLtr = false;
    // Split a string into 'words' for directionality estimation based on
    // relative word counts.
    for (String token in text.split(new RegExp(r'\s+'))) {
      if (startsWithRtl(token)) {
        rtlCount++;
        total++;
      } else if (new RegExp(r'^http://').hasMatch(token)) {
        // Checked if token looks like something that must always be LTR even in
        // RTL text, such as a URL.
        hasWeaklyLtr = true;
      } else if (hasAnyLtr(token)) {
        total++;
      } else if (new RegExp(r'\d').hasMatch(token)) {
        // Checked if token contains any numerals.
        hasWeaklyLtr = true;
      }
    }

    if (total == 0) {
      return hasWeaklyLtr ? TextDirection.LTR : TextDirection.UNKNOWN;
    } else if (rtlCount > _RTL_DETECTION_THRESHOLD * total) {
      return TextDirection.RTL;
    } else {
      return TextDirection.LTR;
    }
  }

  /**
   * Replace the double and single quote directly after a Hebrew character in
   * [str] with GERESH and GERSHAYIM. This is most likely the user's intention.
   */
  static String normalizeHebrewQuote(String str) {
    StringBuffer buf = new StringBuffer();
    if (str.length > 0) {
      buf.write(str.substring(0, 1));
    }
    // Start at 1 because we're looking for the patterns [\u0591-\u05f2])" or
    // [\u0591-\u05f2]'.
    for (int i = 1; i < str.length; i++) {
      if (str.substring(i, i+1) == '"'
          && new RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
        buf.write('\u05f4');
      } else if (str.substring(i, i+1) == "'"
          && new RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
        buf.write('\u05f3');
      } else {
        buf.write(str.substring(i, i+1));
      }
    }
    return buf.toString();
  }

  /**
   * Check the estimated directionality of [str], return true if the piece of
   * text should be laid out in RTL direction. If [isHtml] is true, the string
   * is HTML or HTML-escaped.
   */
  static bool detectRtlDirectionality(String str, {bool isHtml: false}) {
    return estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL;
  }
}
part of angular.directive;

/**
 * Allows adding and removing the boolean attributes from the element.
 *
 * Using `<button disabled="{{false}}">` does not work since it would result
 * in `<button disabled="false">` rather than `<button>`.
 * Browsers change behavior based on presence/absence of attribute rather the
 * its value.
 *
 * For this reason we provide alternate `ng-`attribute directives to
 * add/remove boolean attributes such as `<button ng-disabled="{{false}}">`
 * which will result in proper removal of the attribute.
 *
 * The full list of supported attributes are:
 *
 *  - [ng-checked]
 *  - [ng-disabled]
 *  - [ng-multiple]
 *  - [ng-open]
 *  - [ng-readonly]
 *  - [ng-required]
 *  - [ng-selected]
 */
@NgDirective(selector: '[ng-checked]',  map: const {'ng-checked':  '=.checked'})
@NgDirective(selector: '[ng-disabled]', map: const {'ng-disabled': '=.disabled'})
@NgDirective(selector: '[ng-multiple]', map: const {'ng-multiple': '=.multiple'})
@NgDirective(selector: '[ng-open]',     map: const {'ng-open':     '=.open'})
@NgDirective(selector: '[ng-readonly]', map: const {'ng-readonly': '=.readonly'})
@NgDirective(selector: '[ng-required]', map: const {'ng-required': '=.required'})
@NgDirective(selector: '[ng-selected]', map: const {'ng-selected': '=.selected'})
class NgBooleanAttributeDirective {
  NodeAttrs attrs;
  NgBooleanAttributeDirective(NodeAttrs this.attrs);

  _setBooleanAttribute(name, value) => attrs[name] = (toBool(value) ? '' : null);

  set checked(value)   => _setBooleanAttribute('checked',  value);
  set disabled(value)  => _setBooleanAttribute('disabled', value);
  set multiple(value)  => _setBooleanAttribute('multiple', value);
  set open(value)      => _setBooleanAttribute('open',     value);
  set readonly(value)  => _setBooleanAttribute('readonly', value);
  set required(value)  => _setBooleanAttribute('required', value);
  set selected(value)  => _setBooleanAttribute('selected', value);
}

/**
 * In browser some attributes have network side-effect. If the attribute
 * has `{{interpolation}}` in it it may cause browser to fetch bogus URLs.
 *
 * Example: In `<img src="{{username}}.png">` the browser will fetch the image
 * `http://server/{{username}}.png` before Angular has a chance to replace the
 * attribute with data-bound url.
 *
 * For this reason we provide `ng-`prefixed attributes which avoid the issues
 * mentioned above as in this example: `<img ng-src="{{username}}.png">`.
 *
 * The full list of supported attributes are:
 *
 * - [ng-href]
 * - [ng-src]
 * - [ng-srcset]
 */
@NgDirective(selector: '[ng-href]',   map: const {'ng-href':   '@.href'})
@NgDirective(selector: '[ng-src]',    map: const {'ng-src':    '@.src'})
@NgDirective(selector: '[ng-srcset]', map: const {'ng-srcset': '@.srcset'})
class NgSourceDirective {
  NodeAttrs attrs;
  NgSourceDirective(NodeAttrs this.attrs);

  set href(value)   => attrs['href']   = value;
  set src(value)    => attrs['src']    = value;
  set srcset(value) => attrs['srcset'] = value;

}
part of angular.directive;

/**
 * The [NgTemplateElementDirective] allows one to preload an Angular template
 * into the [TemplateCache].  It works on `<template>` and `<script>` elements
 * that have `type="text/ng-template`.  For such elements, The entire contents
 * of the elements are loaded into the [TemplateCache] under the URL specified
 * by the `id` attribute.
 *
 * Sample usage:
 *
 *     <template id="template_1.html" type="text/ng-template">
 *       TEMPLATE 1 CONTENTS
 *     </template>
 *     <script id="template_2.html" type="text/ng-template">
 *       TEMPLATE 2 CONTENTS
 *     </template>
 *
 * Refer [TemplateCache] for a **full example** as well as more information.
 */
@NgDirective(
  selector: 'template[type=text/ng-template]',
  map: const {'id': '@.templateUrl'})
@NgDirective(
  selector: 'script[type=text/ng-template]',
  children: NgAnnotation.IGNORE_CHILDREN,
  map: const {'id': '@.templateUrl'})
class NgTemplateDirective {
  dom.Element element;
  TemplateCache templateCache;

  NgTemplateDirective(dom.Element this.element, TemplateCache this.templateCache);
  set templateUrl(url) => templateCache.put(url, new HttpResponse(200,
      (element.isTemplate ? element.content.innerHtml : element.innerHtml)));
}
Angular.Dart filter
===================

- [Docs](http://ci.angularjs.org/view/Dart/job/angular.dart-master/javadoc/angular.filter/FilterFilter.html)
- [source](https://github.com/angular/angular.dart/blob/master/lib/filter/filter.dart)
part of angular.filter;

/**
 * Converts string to uppercase.
 *
 * Usage:
 *
 *     {{ uppercase_expression | uppercase }}
 */
@NgFilter(name:'uppercase')
class UppercaseFilter {
  call(String text) => text == null ? text : text.toUpperCase();
}
part of angular.directive;

/**
 * Ng-model directive is responsible for reading/writing to the model.
 * The directive itself is headless. (It does not know how to render or what
 * events to listen for.) It is meant to be used with other directives which
 * provide the rendering and listening capabilities. The directive itself
 * knows how to convert the view-value into model-value and vice versa by
 * allowing others to register converters (To be implemented). It also
 * knwos how to (in)validate the model and the form in which it is declared
 * (to be implemented)
 */
@NgDirective(
    selector: '[ng-model]',
    map: const {'ng-model': '&.model'})
class NgModel {
  final Scope _scope;
  Getter getter = ([_]) => null;
  Setter setter = (_, [__]) => null;


  Function _removeWatch = () => null;
  bool _watchCollection;

  Function render = (value) => null;

  NgModel(Scope this._scope) {
    watchCollection = false;
  }

  get watchCollection => _watchCollection;
  set watchCollection(value) {
    if (_watchCollection == value) return;
    _watchCollection = value;
    _removeWatch();
    if (_watchCollection) {
      _removeWatch = _scope.$watchCollection((s) => getter(), (value) => render(value) );
    } else {
      _removeWatch = _scope.$watch((s) => getter(), (value) => render(value) );
    }
  }

  set model(BoundExpression boundExpression) {
    getter = boundExpression;
    setter = boundExpression.assign;
  }

  // TODO(misko): right now viewValue and modelValue are the same,
  // but this needs to be changed to support converters and form validation
  get viewValue        => modelValue;
  set viewValue(value) => modelValue = value;

  get modelValue        => getter();
  set modelValue(value) => setter(value);
}

/**
 * The UI portion of the ng-model directive. This directive registers the UI
 * events and provides a rendering function for the ng-model directive.
 */
@NgDirective(selector: 'input[type=text][ng-model]')
class InputTextDirective {
  dom.InputElement inputElement;
  NgModel ngModel;
  Scope scope;

  InputTextDirective(dom.Element this.inputElement, NgModel this.ngModel, Scope this.scope) {
    ngModel.render = (value) {
      if (value == null) value = '';

      var currentValue = inputElement.value;
      if (value == currentValue) return;

      var start = inputElement.selectionStart;
      var end = inputElement.selectionEnd;
      inputElement.value = value;
      inputElement.selectionStart = start;
      inputElement.selectionEnd = end;
    };
    inputElement.onChange.listen(relaxFnArgs(processValue));
    inputElement.onKeyDown.listen((e) => new async.Timer(Duration.ZERO, processValue));
  }

  processValue() {
    var value = inputElement.value;
    if (value != ngModel.viewValue) {
      scope.$apply(() => ngModel.viewValue = value);
    }
  }
}

/**
 * The UI portion of the ng-model directive. This directive registers the UI
 * events and provides a rendering function for the ng-model directive.
 */
@NgDirective(selector: 'input[type=checkbox][ng-model]')
class InputCheckboxDirective {
  dom.InputElement inputElement;
  NgModel ngModel;
  Scope scope;

  InputCheckboxDirective(dom.Element this.inputElement, NgModel this.ngModel, Scope this.scope) {
    ngModel.render = (value) {
      inputElement.checked = value == null ? false : toBool(value);
    };
    inputElement.onChange.listen((value) {
      scope.$apply(() => ngModel.viewValue = inputElement.checked);
    });
  }
}
part of angular.directive;

// NOTE(deboer): onXX functions are now typed as 'var' instead of 'Getter'
// to work-around https://code.google.com/p/dart/issues/detail?id=13519

/**
 * Allows you to specify custom behavior for DOM UI events such as mouse,
 * keyboard and touch events.
 *
 * The custom behavior is specified via an Angular binding expression specified
 * on the `ng-`*event* directive (e.g. `ng-click`).  This expression is evaluated
 * on the correct `scope` every time the event occurs.  The event is available
 * to the expression as `$event`.
 *
 * This is more secure than inline DOM handlers in HTML that execute arbitrary
 * JavaScript code and have access to globals instead of the scope without the
 * safety constraints of the Angular expression language.
 *
 * Example:
 *
 *     <button ng-click="lastEvent='Click'"
 *             ng-doubleclick="lastEvent='DblClick'">
 *         Button
 *     </button>
 *
 * The full list of supported handlers are:
 *
 * - [ng-blur]
 * - [ng-change]
 * - [ng-click]
 * - [ng-contextmenu]
 * - [ng-doubleclick]
 * - [ng-drag]
 * - [ng-dragend]
 * - [ng-dragenter]
 * - [ng-dragleave]
 * - [ng-dragover]
 * - [ng-dragstart]
 * - [ng-drop]
 * - [ng-focus]
 * - [ng-keydown]
 * - [ng-keypress]
 * - [ng-keyup]
 * - [ng-mousedown]
 * - [ng-mouseenter]
 * - [ng-mouseleave]
 * - [ng-mousemove]
 * - [ng-mouseout]
 * - [ng-mouseover]
 * - [ng-mouseup]
 * - [ng-mousewheel]
 * - [ng-scroll]
 * - [ng-touchcancel]
 * - [ng-touchend]
 * - [ng-touchmove]
 * - [ng-touchstart]
 */
@NgDirective(selector: '[ng-blur]',        map: const {'ng-blur':        '&.onBlur'})
@NgDirective(selector: '[ng-change]',      map: const {'ng-change':      '&.onChange'})
@NgDirective(selector: '[ng-click]',       map: const {'ng-click':       '&.onClick'})
@NgDirective(selector: '[ng-contextmenu]', map: const {'ng-contextmenu': '&.onContextMenu'})
@NgDirective(selector: '[ng-doubleclick]', map: const {'ng-doubleclick': '&.onDoubleClick'})
@NgDirective(selector: '[ng-drag]',        map: const {'ng-drag':        '&.onDrag'})
@NgDirective(selector: '[ng-dragend]',     map: const {'ng-dragend':     '&.onDragEnd'})
@NgDirective(selector: '[ng-dragenter]',   map: const {'ng-dragenter':   '&.onDragEnter'})
@NgDirective(selector: '[ng-dragleave]',   map: const {'ng-dragleave':   '&.onDragLeave'})
@NgDirective(selector: '[ng-dragover]',    map: const {'ng-dragover':    '&.onDragOver'})
@NgDirective(selector: '[ng-dragstart]',   map: const {'ng-dragstart':   '&.onDragStart'})
@NgDirective(selector: '[ng-drop]',        map: const {'ng-drop':        '&.onDrop'})
@NgDirective(selector: '[ng-focus]',       map: const {'ng-focus':       '&.onFocus'})
@NgDirective(selector: '[ng-keydown]',     map: const {'ng-keydown':     '&.onKeyDown'})
@NgDirective(selector: '[ng-keypress]',    map: const {'ng-keypress':    '&.onKeyPress'})
@NgDirective(selector: '[ng-keyup]',       map: const {'ng-keyup':       '&.onKeyUp'})
@NgDirective(selector: '[ng-mousedown]',   map: const {'ng-mousedown':   '&.onMouseDown'})
@NgDirective(selector: '[ng-mouseenter]',  map: const {'ng-mouseenter':  '&.onMouseEnter'})
@NgDirective(selector: '[ng-mouseleave]',  map: const {'ng-mouseleave':  '&.onMouseLeave'})
@NgDirective(selector: '[ng-mousemove]',   map: const {'ng-mousemove':   '&.onMouseMove'})
@NgDirective(selector: '[ng-mouseout]',    map: const {'ng-mouseout':    '&.onMouseOut'})
@NgDirective(selector: '[ng-mouseover]',   map: const {'ng-mouseover':   '&.onMouseOver'})
@NgDirective(selector: '[ng-mouseup]',     map: const {'ng-mouseup':     '&.onMouseUp'})
@NgDirective(selector: '[ng-mousewheel]',  map: const {'ng-mousewheel':  '&.onMouseWheel'})
@NgDirective(selector: '[ng-scroll]',      map: const {'ng-scroll':      '&.onScroll'})
@NgDirective(selector: '[ng-touchcancel]', map: const {'ng-touchcancel': '&.onTouchCancel'})
@NgDirective(selector: '[ng-touchend]',    map: const {'ng-touchend':    '&.onTouchEnd'})
@NgDirective(selector: '[ng-touchmove]',   map: const {'ng-touchmove':   '&.onTouchMove'})
@NgDirective(selector: '[ng-touchstart]',  map: const {'ng-touchstart':  '&.onTouchStart'})
class NgEventDirective {

  // NOTE: Do not use the element.on['some_event'].listen(...) syntax.  Doing so
  //     has two downsides:
  //     - it loses the event typing
  //     - some DOM events may have multiple platform-dependent event names
  //       under the covers.  The standard Stream getters you will get the
  //       platform specific event name automatically but you're on your own if
  //       you use the on[] syntax.  This also applies to $dom_addEventListener.
  //     Ref: http://api.dartlang.org/docs/releases/latest/dart_html/Events.html
  initListener(var stream, var handler) {
    int key = stream.hashCode;
    if (!listeners.containsKey(key)) {
      listeners[key] = handler;
      stream.listen((event) => scope.$apply(() {
        handler({r"$event": event});
      }));
    }
  }

  set onBlur(value)        => initListener(element.onBlur,        value);
  set onChange(value)      => initListener(element.onChange,      value);
  set onClick(value)       => initListener(element.onClick,       value);
  set onContextMenu(value) => initListener(element.onContextMenu, value);
  set onDoubleClick(value) => initListener(element.onDoubleClick, value);
  set onDrag(value)        => initListener(element.onDrag,        value);
  set onDragEnd(value)     => initListener(element.onDragEnd,     value);
  set onDragEnter(value)   => initListener(element.onDragEnter,   value);
  set onDragLeave(value)   => initListener(element.onDragLeave,   value);
  set onDragOver(value)    => initListener(element.onDragOver,    value);
  set onDragStart(value)   => initListener(element.onDragStart,   value);
  set onDrop(value)        => initListener(element.onDrop,        value);
  set onFocus(value)       => initListener(element.onFocus,       value);
  set onKeyDown(value)     => initListener(element.onKeyDown,     value);
  set onKeyPress(value)    => initListener(element.onKeyPress,    value);
  set onKeyUp(value)       => initListener(element.onKeyUp,       value);
  set onMouseDown(value)   => initListener(element.onMouseDown,   value);
  set onMouseEnter(value)  => initListener(element.onMouseEnter,  value);
  set onMouseLeave(value)  => initListener(element.onMouseLeave,  value);
  set onMouseMove(value)   => initListener(element.onMouseMove,   value);
  set onMouseOut(value)    => initListener(element.onMouseOut,    value);
  set onMouseOver(value)   => initListener(element.onMouseOver,   value);
  set onMouseUp(value)     => initListener(element.onMouseUp,     value);
  set onMouseWheel(value)  => initListener(element.onMouseWheel,  value);
  set onScroll(value)      => initListener(element.onScroll,      value);
  set onTouchCancel(value) => initListener(element.onTouchCancel, value);
  set onTouchEnd(value)    => initListener(element.onTouchEnd,    value);
  set onTouchMove(value)   => initListener(element.onTouchMove,   value);
  set onTouchStart(value)  => initListener(element.onTouchStart,  value);

  // Is it better to use a map of listeners or have 29 properties on this
  // object?  One would pretty much only assign to one or two of those
  // properties.  I'm opting for the map since it's less boilerplate code.
  var listeners = {};
  dom.Element element;
  Scope scope;

  NgEventDirective(dom.Element this.element, Scope this.scope);
}
part of angular.directive;

/**
 * The ngHide directive shows or hides the given HTML element based on the
 * expression provided to the ngHide attribute. The element is shown or hidden
 * by changing the removing or adding the ng-hide CSS class onto the element.
 */
@NgDirective(
    selector: '[ng-hide]',
    map: const {'ng-hide': '=.hide'} )
class NgHideDirective {
  static String NG_HIDE_CLASS = 'ng-hide';

  dom.Element element;

  NgHideDirective(dom.Element this.element);

  set hide(value) {
    if (toBool(value)) {
      element.classes.add(NG_HIDE_CLASS);
    } else {
      element.classes.remove(NG_HIDE_CLASS);
    }
  }
}

/**
 * The ngShow directive shows or hides the given HTML element based on the
 * expression provided to the ngHide attribute. The element is shown or hidden
 * by changing the removing or adding the ng-hide CSS class onto the element.
 */
@NgDirective(
    selector: '[ng-show]',
    map: const {'ng-show': '=.show'})
class NgShowDirective {
  static String NG_SHOW_CLASS = 'ng-show';

  dom.Element element;

  NgShowDirective(dom.Element this.element);

  set show(value) {
    if (toBool(value)) {
      element.classes.add(NG_SHOW_CLASS);
    } else {
      element.classes.remove(NG_SHOW_CLASS);
    }
  }
}

part of angular.core.parser;

class StaticParserFunctions {
  StaticParserFunctions(Map this.functions);

  Map<String, dynamic> functions;
}

class StaticParser implements Parser {
  Map<String, dynamic> _functions;
  Parser _fallbackParser;

  StaticParser(StaticParserFunctions functions,
               DynamicParser this._fallbackParser) {
    assert(functions != null);
    _functions = functions.functions;
  }

  call(String exp) {
    if (exp == null) exp = "";
    if (!_functions.containsKey(exp)) {
      //print("Expression [$exp] is not supported in static parser");
      return _fallbackParser.call(exp);
    }
    return _functions[exp];
  }

  primaryFromToken(Token token, parserError) {
    throw 'Not Implemented';
  }
}
part of angular.filter;

/**
 * Formats a number as text.
 *
 * If the input is not a number an empty string is returned.
 *
 *
 * Usage:
 *
 *     {{ number_expression | number[:fractionSize] }}
 *
 */
@NgFilter(name:'number')
class NumberFilter {

  Map<num, NumberFormat> nfs = new Map<num, NumberFormat>();

  /**
   *  [value]: the value to format
   *
   *  [fractionSize]: Number of decimal places to round the number to. If this
   *    is not provided then the fraction size is computed from the current
   *    locale's number formatting pattern. In the case of the default locale,
   *    it will be 3.
   */
  call(value, [fractionSize = null]) {
    if (value is String) value = double.parse(value);
    if (!(value is num)) return value;
    if (value.isNaN) return '';
    var nf = nfs[fractionSize];
    if (nf == null) {
      nf = new NumberFormat();
      nf.maximumIntegerDigits = 9;
      if (fractionSize != null) {
        nf.minimumFractionDigits = fractionSize;
        nf.maximumFractionDigits = fractionSize;
      }
      nfs[fractionSize] = nf;
    }
    return nf.format(value);
  }
}
// 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.

(function() {
// Bootstrap support for Dart scripts on the page as this script.
if (navigator.webkitStartDart) {
  if (!navigator.webkitStartDart()) {
    document.body.innerHTML = 'This build has expired.  Please download a new Dartium at http://www.dartlang.org/dartium/index.html';
  }
} else {
  // TODO:
  // - Support in-browser compilation.
  // - Handle inline Dart scripts.

  // Fall back to compiled JS. Run through all the scripts and
  // replace them if they have a type that indicate that they source
  // in Dart code.
  //
  //   <script type="application/dart" src="..."></script>
  //
  var scripts = document.getElementsByTagName("script");
  var length = scripts.length;
  for (var i = 0; i < length; ++i) {
    if (scripts[i].type == "application/dart") {
      // Remap foo.dart to foo.dart.js.
      if (scripts[i].src && scripts[i].src != '') {
        var script = document.createElement('script');
        script.src = scripts[i].src.replace(/\.dart(?=\?|$)/, '.dart.js');
        var parent = scripts[i].parentNode;
        // TODO(vsm): Find a solution for issue 8455 that works with more
        // than one script.
        document.currentScript = script;
        parent.replaceChild(script, scripts[i]);
      }
    }
  }
}
})();
part of angular.filter;

/**
 * Formats date to a string based on the requested format.
 * See Dart http://api.dartlang.org/docs/releases/latest/intl/DateFormat.html
 * for full formating options.
 *
 * - `medium`: equivalent to `MMM d, y h:mm:ss a` for en_US locale (e.g. Sep 3, 2010 12:05:08 pm)
 * - `short`: equivalent to `M/d/yy h:mm a` for en_US locale (e.g. 9/3/10 12:05 pm)
 * - `fullDate`: equivalent to `EEEE, MMMM d, y` for en_US locale (e.g. Friday, September 3, 2010)
 * - `longDate`: equivalent to `MMMM d, y` for en_US locale (e.g. September 3, 2010)
 * - `mediumDate`: equivalent to `MMM d, y` for en_US locale (e.g. Sep 3, 2010)
 * - `shortDate`: equivalent to `M/d/yy` for en_US locale (e.g. 9/3/10)
 * - `mediumTime`: equivalent to `h:mm:ss a` for en_US locale (e.g. 12:05:08 pm)
 * - `shortTime`: equivalent to `h:mm a` for en_US locale (e.g. 12:05 pm)
 *
 *
 * Usage:
 *
 *     {{ date_expression | date[:format] }}
 *
 */
@NgFilter(name:'date')
class DateFilter {

  static Map<String, String> MAP = {
    'medium':     'MMM d, y h:mm:ss a',
    'short':      'M/d/yy h:mm a',
    'fullDate':   'EEEE, MMMM d, y',
    'longDate':   'MMMM d, y',
    'mediumDate': 'MMM d, y',
    'shortDate':  'M/d/yy',
    'mediumTime': 'h:mm:ss a',
    'shortTime':  'h:mm a',
  };

  Map<num, NumberFormat> nfs = new Map<num, NumberFormat>();

  /**
   *  [date]: Date to format either as Date object, milliseconds
   *    ([string] or [num]) or various ISO 8601 datetime string formats
   *    (e.g. `yyyy-MM-ddTHH:mm:ss.SSSZ` and its shorter versions like
   *    `yyyy-MM-ddTHH:mmZ`, `yyyy-MM-dd` or `yyyyMMddTHHmmssZ`). If no
   *    timezone is specified in the string input, the time is considered to
   *    be in the local timezone.
   *
   *  [format]: Formatting rules (see Description). If not specified,
   *    mediumDate is used
   *
   */
  call(date, [format = r'mediumDate']) {
    if (date == '' || date == null) return date;
    if (date is String) date = DateTime.parse(date);
    if (date is num) date = new DateTime.fromMillisecondsSinceEpoch(date);
    if (!(date is DateTime)) return date;
    var nf = nfs[format];
    if (nf == null) {
      if (MAP.containsKey(format)) {
        format = MAP[format];
      }
      nf = new DateFormat(format);
    }
    return nf.format(date);
  }
}
library di;

export 'module.dart';
export 'injector.dart';
export 'errors.dart';
part of angular.filter;

/**
 * Allows you to convert a JavaScript object into JSON string. This filter is
 * mostly useful for debugging.
 *
 * Usage:
 *
 *     {{ json_expression | json }}
 */
@NgFilter(name:'json')
class JsonFilter {
  call(text) => stringify(text);
}
// 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.

part of intl;

/**
 * Bidi stands for Bi-directional text.
 * According to [Wikipedia](http://en.wikipedia.org/wiki/Bi-directional_text):
 * Bi-directional text is text containing text in both text directionalities,
 * both right-to-left (RTL) and left-to-right (LTR). It generally involves text
 * containing different types of alphabets, but may also refer to boustrophedon,
 * which is changing text directionality in each row.
 *
 * Utility class for formatting display text in a potentially
 * opposite-directionality context without garbling layout issues.
 * Mostly a very "slimmed-down" and dart-ified port of the Closure Birectional
 * formatting libary. If there is a utility in the Closure library (or ICU, or
 * elsewhere) that you would like this formatter to make available, please
 * contact the Dart team.
 *
 * Provides the following functionality:
 *
 * 1. *BiDi Wrapping*
 * When text in one language is mixed into a document in another, opposite-
 * directionality language, e.g. when an English business name is embedded in a
 * Hebrew web page, both the inserted string and the text following it may be
 * displayed incorrectly unless the inserted string is explicitly separated
 * from the surrounding text in a "wrapper" that declares its directionality at
 * the start and then resets it back at the end. This wrapping can be done in
 * HTML mark-up (e.g. a 'span dir=rtl' tag) or - only in contexts where mark-up
 * can not be used - in Unicode BiDi formatting codes (LRE|RLE and PDF).
 * Providing such wrapping services is the basic purpose of the BiDi formatter.
 *
 * 2. *Directionality estimation*
 * How does one know whether a string about to be inserted into surrounding
 * text has the same directionality? Well, in many cases, one knows that this
 * must be the case when writing the code doing the insertion, e.g. when a
 * localized message is inserted into a localized page. In such cases there is
 * no need to involve the BiDi formatter at all. In the remaining cases, e.g.
 * when the string is user-entered or comes from a database, the language of
 * the string (and thus its directionality) is not known a priori, and must be
 * estimated at run-time. The BiDi formatter does this automatically.
 *
 * 3. *Escaping*
 * When wrapping plain text - i.e. text that is not already HTML or HTML-
 * escaped - in HTML mark-up, the text must first be HTML-escaped to prevent XSS
 * attacks and other nasty business. This of course is always true, but the
 * escaping cannot be done after the string has already been wrapped in
 * mark-up, so the BiDi formatter also serves as a last chance and includes
 * escaping services.
 *
 * Thus, in a single call, the formatter will escape the input string as
 * specified, determine its directionality, and wrap it as necessary. It is
 * then up to the caller to insert the return value in the output.
 */

class BidiFormatter {

  /** The direction of the surrounding text (the context). */
  TextDirection contextDirection;

  /**
   * Indicates if we should always wrap the formatted text in a &lt;span&lt;,.
   */
  bool _alwaysSpan;

  /**
   * Create a formatting object with a direction. If [alwaysSpan] is true we
   * should always use a `span` tag, even when the input directionality is
   * neutral or matches the context, so that the DOM structure of the output
   * does not depend on the combination of directionalities.
   */
  BidiFormatter.LTR([alwaysSpan=false]) : contextDirection = TextDirection.LTR,
      _alwaysSpan = alwaysSpan;
  BidiFormatter.RTL([alwaysSpan=false]) : contextDirection = TextDirection.RTL,
      _alwaysSpan = alwaysSpan;
  BidiFormatter.UNKNOWN([alwaysSpan=false]) :
      contextDirection = TextDirection.UNKNOWN, _alwaysSpan = alwaysSpan;

  /** Is true if the known context direction for this formatter is RTL. */
  bool get isRTL => contextDirection == TextDirection.RTL;

  /**
   * Escapes HTML-special characters of [text] so that the result can be
   * included verbatim in HTML source code, either in an element body or in an
   * attribute value.
   *
   * *htmlEscape* is deprecated. Use [HtmlEscape] from the `dart:convert`
   * package. *htmlEscape* will be removed the 30th of September 2013.
   */
  // TODO(kevmoo) Remove this!
  @deprecated
  String htmlEscape(String text) => HTML_ESCAPE.convert(text);

  /**
   * Formats a string of a given (or estimated, if not provided)
   * [direction] for use in HTML output of the context directionality, so
   * an opposite-directionality string is neither garbled nor garbles what
   * follows it.
   * If the input string's directionality doesn't match the context
   * directionality, we wrap it with a `span` tag and add a `dir` attribute
   * (either "dir=rtl" or "dir=ltr").
   * If alwaysSpan was true when constructing the formatter, the input is always
   * wrapped with `span` tag, skipping the dir attribute when it's not needed.
   *
   * If [resetDir] is true and the overall directionality or the exit
   * directionality of [text] is opposite to the context directionality,
   * a trailing unicode BiDi mark matching the context directionality is
   * appended (LRM or RLM). If [isHtml] is false, we HTML-escape the [text].
   */
  String wrapWithSpan(String text, {bool isHtml: false, bool resetDir: true,
                      TextDirection direction}) {
    if (direction == null) direction = estimateDirection(text, isHtml: isHtml);
    var result;
    if (!isHtml) text = HTML_ESCAPE.convert(text);
    var directionChange = contextDirection.isDirectionChange(direction);
    if (_alwaysSpan || directionChange) {
      var spanDirection = '';
      if (directionChange) {
        spanDirection = ' dir=${direction.spanText}';
      }
      result= '<span$spanDirection>$text</span>';
    } else {
      result = text;
    }
    return result + (resetDir? _resetDir(text, direction, isHtml) : '');
  }

  /**
   * Format [text] of a known (if specified) or estimated [direction] for use
   * in *plain-text* output of the context directionality, so an
   * opposite-directionality text is neither garbled nor garbles what follows
   * it. Unlike wrapWithSpan, this makes use of unicode BiDi formatting
   * characters instead of spans for wrapping. The returned string would be
   * RLE+text+PDF for RTL text, or LRE+text+PDF for LTR text.
   *
   * If [resetDir] is true, and if the overall directionality or the exit
   * directionality of text are opposite to the context directionality,
   * a trailing unicode BiDi mark matching the context directionality is
   * appended (LRM or RLM).
   *
   * In HTML, the *only* valid use of this function is inside of elements that
   * do not allow markup, e.g. an 'option' tag.
   * This function does *not* do HTML-escaping regardless of the value of
   * [isHtml]. [isHtml] is used to designate if the text contains HTML (escaped
   * or unescaped).
   */
  String wrapWithUnicode(String text, {bool isHtml: false, bool resetDir: true,
                         TextDirection direction}) {
    if (direction == null) direction = estimateDirection(text, isHtml: isHtml);
    var result = text;
    if (contextDirection.isDirectionChange(direction)) {
      var marker = direction == TextDirection.RTL ? Bidi.RLE : Bidi.LRE;
      result = "${marker}$text${Bidi.PDF}";

    }
    return result + (resetDir? _resetDir(text, direction, isHtml) : '');
  }

  /**
   * Estimates the directionality of [text] using the best known
   * general-purpose method (using relative word counts). A
   * TextDirection.UNKNOWN return value indicates completely neutral input.
   * [isHtml] is true if [text] HTML or HTML-escaped.
   */
  TextDirection estimateDirection(String text, {bool isHtml: false}) {
    return Bidi.estimateDirectionOfText(text, isHtml: isHtml); //TODO~!!!
  }

  /**
   * Returns a unicode BiDi mark matching the surrounding context's [direction]
   * (not necessarily the direction of [text]). The function returns an LRM or
   * RLM if the overall directionality or the exit directionality of [text] is
   * opposite the context directionality. Otherwise
   * return the empty string. [isHtml] is true if [text] is HTML or
   * HTML-escaped.
   */
  String _resetDir(String text, TextDirection direction, bool isHtml) {
    // endsWithRtl and endsWithLtr are called only if needed (short-circuit).
    if ((contextDirection == TextDirection.LTR &&
          (direction == TextDirection.RTL ||
           Bidi.endsWithRtl(text, isHtml))) ||
        (contextDirection == TextDirection.RTL &&
          (direction == TextDirection.LTR ||
           Bidi.endsWithLtr(text, isHtml)))) {
      if (contextDirection == TextDirection.LTR) {
        return Bidi.LRM;
      } else {
        return Bidi.RLM;
      }
    } else {
      return '';
    }
  }
}
part of angular.core.dom;

class NullTreeSanitizer implements dom.NodeTreeSanitizer {
  void sanitizeTree(dom.Node node) {}
}
part of angular.core.dom;


/**
 * BoundBlockFactory is a [BlockFactory] which does not need Injector because
 * it is pre-bound to an injector from the parent. This means that this
 * BoundBlockFactory can only be used from within a specific Directive such
 * as [NgRepeat], but it can not be stored in a cache.
 *
 * The BoundBlockFactory needs [Scope] to be created.
 */

class BoundBlockFactory {
  BlockFactory blockFactory;

  Injector injector;

  BoundBlockFactory(BlockFactory this.blockFactory, Injector this.injector);

  Block call(Scope scope) {
    return blockFactory(injector.createChild([new Module()..value(Scope, scope)]));
  }
}

/**
 * BlockFactory is used to create new [Block]s. BlockFactory is created by the
 * [Compiler] as a result of compiling a template.
 */

class BlockFactory {
  List directivePositions;

  List<dom.Node> templateElements;

  Profiler _perf;

  BlockFactory(this.templateElements, this.directivePositions, this._perf);

  BoundBlockFactory bind(Injector injector) {
    return new BoundBlockFactory(this, injector);
  }

  Block call(Injector injector, [List<dom.Node> elements]) {
    if (elements == null) {
      elements = cloneElements(templateElements);
    }
    var block = new Block(elements);
    _link(block, elements, directivePositions, injector);
    return block;
  }

  _link(Block block, List<dom.Node> nodeList, List directivePositions, Injector parentInjector) {
    var preRenderedIndexOffset = 0;
    var directiveDefsByName = {
    };

    for (num i = 0, ii = directivePositions.length; i < ii;) {
      num index = directivePositions[i++];

      List<DirectiveRef> directiveRefs = directivePositions[i++];
      List childDirectivePositions = directivePositions[i++];
      var nodeListIndex = index + preRenderedIndexOffset;
      dom.Node node = nodeList[nodeListIndex];

      // if node isn't attached to the DOM, create a parent for it.
      var parentNode = node.parentNode;
      var fakeParent = false;
      if (parentNode == null) {
        fakeParent = true;
        parentNode = new dom.DivElement();
        parentNode.append(node);
      }

      var childInjector = _instantiateDirectives(block, parentInjector, node,
                      directiveRefs, parentInjector.get(Parser));

      if (childDirectivePositions != null) {
        _link(block, node.nodes, childDirectivePositions, childInjector);
      }

      if (fakeParent) {
        // extract the node from the parentNode.
        nodeList[nodeListIndex] = parentNode.nodes[0];
      }
    }
  }

  Injector _instantiateDirectives(Block block, Injector parentInjector,
                                  dom.Node node, List<DirectiveRef> directiveRefs,
                                  Parser parser) =>
    _perf.time('angular.blockFactory.instantiateDirectives', () {
    if (directiveRefs == null || directiveRefs.length == 0) return parentInjector;
    var nodeModule = new Module();
    var blockHoleFactory = (_) => null;
    var blockFactory = (_) => null;
    var boundBlockFactory = (_) => null;
    var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null;
    var nodesAttrsDirectives = null;
    Map<Type, _ComponentFactory> fctrs;

    nodeModule.value(Block, block);
    nodeModule.value(dom.Element, node);
    nodeModule.value(dom.Node, node);
    nodeModule.value(NodeAttrs, nodeAttrs);
    directiveRefs.forEach((DirectiveRef ref) {
      NgAnnotation annotation = ref.annotation;
      var visibility = _elementOnly;
      if (ref.annotation.visibility == NgDirective.CHILDREN_VISIBILITY) {
        visibility = null;
      } else if (ref.annotation.visibility == NgDirective.DIRECT_CHILDREN_VISIBILITY) {
        visibility = _elementDirectChildren;
      }
      if (ref.type == NgTextMustacheDirective) {
        nodeModule.factory(NgTextMustacheDirective, (Injector injector) {
          return new NgTextMustacheDirective(
              node, ref.value, injector.get(Interpolate), injector.get(Scope),
              injector.get(TextChangeListener));
        });
      } else if (ref.type == NgAttrMustacheDirective) {
        if (nodesAttrsDirectives == null) {
          nodesAttrsDirectives = [];
          nodeModule.factory(NgAttrMustacheDirective, (Injector injector) {
            nodesAttrsDirectives.forEach((ref) {
              new NgAttrMustacheDirective(nodeAttrs, ref.value, injector.get(Interpolate), injector.get(Scope));
            });
          });
        }
        nodesAttrsDirectives.add(ref);
      } else if (ref.annotation is NgComponent) {
        //nodeModule.factory(type, new ComponentFactory(node, ref.directive), visibility: visibility);
        // TODO(misko): there should be no need to wrap function like this.
        nodeModule.factory(ref.type, (Injector injector) {
          Compiler compiler = injector.get(Compiler);
          Scope scope = injector.get(Scope);
          BlockCache blockCache = injector.get(BlockCache);
          Http http = injector.get(Http);
          TemplateCache templateCache = injector.get(TemplateCache);
          // This is a bit of a hack since we are returning different type then we are.
          var componentFactory = new _ComponentFactory(node, ref.type, ref.annotation as NgComponent, injector.get(dom.NodeTreeSanitizer));
          if (fctrs == null) fctrs = new Map<Type, _ComponentFactory>();
          fctrs[ref.type] = componentFactory;
          return componentFactory(injector, compiler, scope, blockCache, http, templateCache);
        }, visibility: visibility);
      } else {
        nodeModule.type(ref.type, visibility: visibility);
      }
      for (var publishType in ref.annotation.publishTypes) {
        nodeModule.factory(publishType, (Injector injector) => injector.get(ref.type), visibility: visibility);
      }
      if (annotation.children == NgAnnotation.TRANSCLUDE_CHILDREN) {
        // Currently, transclude is only supported for NgDirective.
        assert(annotation is NgDirective);
        blockHoleFactory = (_) => new BlockHole([node]);
        blockFactory = (_) => ref.blockFactory;
        boundBlockFactory = (Injector injector) => ref.blockFactory.bind(injector);
      }
    });
    nodeModule.factory(BlockHole, blockHoleFactory);
    nodeModule.factory(BlockFactory, blockFactory);
    nodeModule.factory(BoundBlockFactory, boundBlockFactory);
    var nodeInjector = parentInjector.createChild([nodeModule]);
    var scope = nodeInjector.get(Scope);
    directiveRefs.forEach((ref) {
      var controller = nodeInjector.get(ref.type);
      var shadowScope = (fctrs != null && fctrs.containsKey(ref.type)) ? fctrs[ref.type].shadowScope : null;
      if (ref.annotation.publishAs != null) {
        (shadowScope == null ? scope : shadowScope)[ref.annotation.publishAs] = controller;
      }
      _createAttributeMapping(ref.annotation, nodeAttrs == null ? new _AnchorAttrs(ref) : nodeAttrs, scope, shadowScope, controller, parser);
      if (controller is NgAttachAware) {
        var removeWatcher;
        removeWatcher = scope.$watch(() {
          removeWatcher();
          controller.attach();
        });
      }
      if (controller is NgDetachAware) {
        scope.$on(r'$destroy', controller.detach);
      }
    });
    return nodeInjector;
  });

  // DI visibility callback allowing node-local visibility.

  bool _elementOnly(Injector requesting, Injector defining) {
    if (requesting.name == _SHADOW) {
      requesting = requesting.parent;
    }
    return identical(requesting, defining);
  }

  // DI visibility callback allowing visibility from direct child into parent.

  bool _elementDirectChildren(Injector requesting, Injector defining) {
    if (requesting.name == _SHADOW) {
      requesting = requesting.parent;
    }
    return _elementOnly(requesting, defining) || identical(requesting.parent, defining);
  }
}

/**
 * BlockCache is used to cache the compilation of templates into [Block]s.
 * It can be used synchronously if HTML is known or asynchronously if the
 * template HTML needs to be looked up from the URL.
 */

class BlockCache {
  // _blockFactoryCache is unbounded
  Cache<String, BlockFactory> _blockFactoryCache =
      new LruCache<String, BlockFactory>(capacity: 0);

  Http $http;

  TemplateCache $templateCache;

  Compiler compiler;

  dom.NodeTreeSanitizer treeSanitizer;

  BlockCache(Http this.$http, TemplateCache this.$templateCache, Compiler this.compiler, dom.NodeTreeSanitizer this.treeSanitizer);

  BlockFactory fromHtml(String html) {
    BlockFactory blockFactory = _blockFactoryCache.get(html);
    if (blockFactory == null) {
      var div = new dom.Element.tag('div');
      div.setInnerHtml(html, treeSanitizer: treeSanitizer);
      blockFactory = compiler(div.nodes);
      _blockFactoryCache.put(html, blockFactory);
    }
    return blockFactory;
  }

  async.Future<BlockFactory> fromUrl(String url) {
    return $http.getString(url, cache: $templateCache).then((String tmpl) {
      return fromHtml(tmpl);
    });
  }
}

/**
 * ComponentFactory is responsible for setting up components. This includes
 * the shadowDom, fetching template, importing styles, setting up attribute
 * mappings, publishing the controller, and compiling and caching the template.
 */

class _ComponentFactory {

  final dom.Element element;
  final Type type;
  final NgComponent component;
  final dom.NodeTreeSanitizer treeSanitizer;

  dom.ShadowRoot shadowDom;
  Scope shadowScope;
  Injector shadowInjector;
  Compiler compiler;
  var controller;

  _ComponentFactory(this.element, Type this.type, NgComponent this.component, this.treeSanitizer);

  dynamic call(Injector injector, Compiler compiler, Scope scope, BlockCache $blockCache, Http $http, TemplateCache $templateCache) {
    this.compiler = compiler;
    shadowDom = element.createShadowRoot();
    shadowDom.applyAuthorStyles = component.applyAuthorStyles;
    shadowDom.resetStyleInheritance = component.resetStyleInheritance;

    shadowScope = scope.$new(true);
    // TODO(pavelgj): fetching CSS with Http is mainly an attempt to
    // work around an unfiled Chrome bug when reloading same CSS breaks
    // styles all over the page. We shouldn't be doing browsers work,
    // so change back to using @import once Chrome bug is fixed or a
    // better work around is found.
    async.Future<String> cssFuture;
    if (component.cssUrl != null) {
      cssFuture = $http.getString(component.cssUrl, cache: $templateCache);
    } else {
      cssFuture = new async.Future.value(null);
    }
    var blockFuture;
    if (component.template != null) {
      blockFuture = new async.Future.value($blockCache.fromHtml(component.template));
    } else if (component.templateUrl != null) {
      blockFuture = $blockCache.fromUrl(component.templateUrl);
    }
    TemplateLoader templateLoader = new TemplateLoader(cssFuture.then((String css) {
      if (css != null) {
        shadowDom.setInnerHtml('<style>$css</style>', treeSanitizer: treeSanitizer);
      }
      if (blockFuture != null) {
        return blockFuture.then((BlockFactory blockFactory) => attachBlockToShadowDom(blockFactory));
      }
      return shadowDom;
    }));
    controller = createShadowInjector(injector, templateLoader).get(type);
    return controller;
  }

  attachBlockToShadowDom(BlockFactory blockFactory) {
    var block = blockFactory(shadowInjector);
    shadowDom.nodes.addAll(block.elements);
    return shadowDom;
  }

  createShadowInjector(injector, TemplateLoader templateLoader) {
    var shadowModule = new Module()
        ..type(type)
        ..value(Scope, shadowScope)
        ..value(TemplateLoader, templateLoader)
        ..value(dom.ShadowRoot, shadowDom);
    shadowInjector = injector.createChild([shadowModule], name: _SHADOW);
    return shadowInjector;
  }
}

class _AnchorAttrs extends NodeAttrs {
  DirectiveRef _directiveRef;

  _AnchorAttrs(DirectiveRef this._directiveRef):super(null);

  operator [](name) => name == '.' ? _directiveRef.value : null;

  observe(String attributeName, AttributeChanged notifyFn) {
    if (attributeName == '.') {
      notifyFn(_directiveRef.value);
    } else {
      notifyFn(null);
    }
  }
}


RegExp _MAPPING = new RegExp(r'^([\@\=\&\!])(\.?)\s*(.*)$');

_createAttributeMapping(NgAnnotation annotation, NodeAttrs nodeAttrs,
                        Scope scope, Scope shadowScope, Object controller, Parser parser) {
  if (annotation.map != null) annotation.map.forEach((attrName, mapping) {
    Match match = _MAPPING.firstMatch(mapping);
    if (match == null) {
      throw "Unknown mapping '$mapping' for attribute '$attrName'.";
    }
    var mode = match[1];
    var controllerContext = match[2];
    var dstPath = match[3];
    var context = controllerContext == '.' ? controller : shadowScope;

    Expression dstPathFn = parser(dstPath.isEmpty ? attrName : dstPath);
    if (!dstPathFn.assignable) {
      throw "Expression '$dstPath' is not assignable in mapping '$mapping' for attribute '$attrName'.";
    }
    switch (mode) {
      case '@':
        nodeAttrs.observe(attrName, (value) => dstPathFn.assign(context, value));
        break;
      case '=':
        Expression attrExprFn = parser(nodeAttrs[attrName]);
        var shadowValue = null;
        scope.$watch(() => attrExprFn.eval(scope), (v) => dstPathFn.assign(context, shadowValue = v), nodeAttrs[attrName]);
        if (shadowScope != null) {
          if (attrExprFn.assignable) {
            shadowScope.$watch(() => dstPathFn.eval(context), (v) {
              if (shadowValue != v) {
                shadowValue = v;
                attrExprFn.assign(scope, v);
              }
            });
          }
        }
        break;
      case '!':
        Expression attrExprFn = parser(nodeAttrs[attrName]);
        var stopWatching;
        stopWatching = scope.$watch(() => attrExprFn.eval(scope), (value) {
          if (dstPathFn.assign(context, value) != null) {
            stopWatching();
          }
        }, nodeAttrs[attrName]);
        break;
      case '&':
        dstPathFn.assign(context, parser(nodeAttrs[attrName]).bind(scope));
        break;
    }
  });
}


bool _understands(obj, symbol) {
  if (symbol is String) symbol = new Symbol(symbol);
  return reflect(obj).type.methods.containsKey(symbol);
}

String _SHADOW = 'SHADOW_INJECTOR';

part of angular.core.parser;

class BoundExpression {
  var _context;
  Expression expression;

  BoundExpression(this._context, Expression this.expression);

  call([locals]) => expression.eval(_context, locals);
  assign(value, [locals]) => expression.assign(_context, value, locals);
}

class Expression implements ParserAST {
  final ParsedGetter eval;
  final ParsedSetter assign;

  String exp;
  List parts;

  Expression(ParsedGetter this.eval, [ParsedSetter this.assign]);

  bind(context) => new BoundExpression(context, this);

  get assignable => assign != null;
}

class GetterSetter {
  static stripTrailingNulls(List l) {
    while (l.length > 0 && l.last == null) {
      l.removeLast();
    }
    return l;
  }

  _maybeInvoke(instanceMirror, symbol) {
    if (instanceMirror.type.members.containsKey(symbol)) {
      MethodMirror methodMirror = instanceMirror.type.members[symbol];
      return relaxFnArgs(([a0, a1, a2, a3, a4, a5]) {
        var args = stripTrailingNulls([a0, a1, a2, a3, a4, a5]);
        return instanceMirror.invoke(symbol, args).reflectee;
      });
    }
    return null;
  }
  Function getter(String key) {
    var symbol = new Symbol(key);
    return (o) {
      InstanceMirror instanceMirror = reflect(o);
      try {
        return instanceMirror.getField(symbol).reflectee;
      } on NoSuchMethodError catch (e) {
        var invokeClosure = _maybeInvoke(instanceMirror, symbol);
        if (invokeClosure == null) {
          rethrow;
        }
        return invokeClosure;
      } on UnsupportedError catch (e) {
        var invokeClosure = _maybeInvoke(instanceMirror, symbol);
        if (invokeClosure == null) {
          rethrow;
        }
        return invokeClosure;
      }
    };
  }

  Function setter(String key) {
    var symbol = new Symbol(key);
    return (o, v) {
      reflect(o).setField(symbol, v);
      return v;
    };
  }
}

var undefined_ = const Symbol("UNDEFINED");

class ParserBackend {
  GetterSetter _getterSetter;
  FilterMap _filters;

  ParserBackend(GetterSetter this._getterSetter, FilterMap this._filters);

  static Expression ZERO = new Expression((_, [_x]) => 0);

  getter(String path) {
    List<String> keys = path.split('.');
    List<Function> getters = keys.map(_getterSetter.getter).toList();

    if (getters.isEmpty) {
      return (self, [locals]) => self;
    } else {
      return (dynamic self, [Map locals]) {
        if (self == null) {
          return null;
        }

        // Cache for local closure access
        List<String> _keys = keys;
        List<Function> _getters = getters;
        var _gettersLength = _getters.length;

        num i = 0;
        if (locals != null) {
          dynamic selfNext = locals[_keys[0]];
          if (selfNext == null) {
            if (locals.containsKey(_keys[0])) {
              return null;
            }
          } else {
            i++;
            self = selfNext;
          }
        }
        for (; i < _gettersLength; i++) {
          if (self is Map) {
            self = self[_keys[i]];
          } else {
            self = _getters[i](self);
          }
          if (self == null) {
            return null;
          }
        }
        return self;
      };
    }
  }

  setter(String path) {
    List<String> keys = path.split('.');
    List<Function> getters = keys.map(_getterSetter.getter).toList();
    List<Function> setters = keys.map(_getterSetter.setter).toList();
    return (dynamic self, dynamic value, [Map locals]) {
      num i = 0;
      List<String> _keys = keys;
      List<Function> _getters = getters;
      List<Function> _setters = setters;
      var setterLengthMinusOne = _keys.length - 1;

      dynamic selfNext;
      if (locals != null && i < setterLengthMinusOne) {
        selfNext = locals[_keys[0]];
        if (selfNext == null) {
          if (locals.containsKey(_keys[0])) {
            return null;
          }
        } else {
          i++;
          self = selfNext;
        }
      }

      for (; i < setterLengthMinusOne; i++) {
        if (self is Map) {
          selfNext = self[_keys[i]];
        } else {
          selfNext = _getters[i](self);
        }

        if (selfNext == null) {
          selfNext = {};
          if (self is Map) {
            self[_keys[i]] = selfNext;
          } else {
            _setters[i](self, selfNext);
          }
        }
        self = selfNext;
      }
      if (self is Map) {
        self[_keys[setterLengthMinusOne]] = value;
      } else {
        _setters[i](self, value);
      }
      return value;
    };
  }

  _op(opKey) => OPERATORS[opKey];

  Expression binaryFn(Expression left, String op, Expression right) =>
      new Expression((self, [locals]) => _op(op)(self, locals, left, right));

  Expression unaryFn(String op, Expression right) =>
      new Expression((self, [locals]) => _op(op)(self, locals, right, null));

  Expression assignment(Expression left, Expression right, evalError) =>
      new Expression((self, [locals]) {
        try {
          return left.assign(self, right.eval(self, locals), locals);
        } catch (e, s) {
          throw evalError('Caught $e', s);
        }
      });

  Expression multipleStatements(statements) =>
      new Expression((self, [locals]) {
        var value;
        for ( var i = 0; i < statements.length; i++) {
          var statement = statements[i];
          if (statement != null)
            value = statement.eval(self, locals);
        }
        return value;
      });

  Expression functionCall(fn, fnName, argsFn, evalError) =>
      new Expression((self, [locals]){
        List args = [];
        for ( var i = 0; i < argsFn.length; i++) {
          args.add(argsFn[i].eval(self, locals));
        }
        var userFn = safeFunctionCall(fn.eval(self, locals), fnName, evalError);

        return relaxFnApply(userFn, args);
      });

  Expression arrayDeclaration(elementFns) =>
      new Expression((self, [locals]){
        var array = [];
        for ( var i = 0; i < elementFns.length; i++) {
          array.add(elementFns[i].eval(self, locals));
        }
        return array;
      });

  Expression objectIndex(obj, indexFn, evalError) =>
      new Expression((self, [locals]) {
        var i = indexFn.eval(self, locals);
        var o = obj.eval(self, locals),
        v, p;

        v = objectIndexGetField(o, i, evalError);

        return v;
      }, (self, value, [locals]) =>
          objectIndexSetField(obj.eval(self, locals),
              indexFn.eval(self, locals), value, evalError)
      );

  Expression fieldAccess(object, field) {
    var setterFn = setter(field);
    var getterFn = getter(field);
    return new Expression(
        (self, [locals]) => getterFn(object.eval(self, locals)),
        (self, value, [locals]) => setterFn(object.eval(self, locals), value));
  }

  Expression object(keyValues) =>
      new Expression((self, [locals]){
        var object = {};
        for ( var i = 0; i < keyValues.length; i++) {
          var keyValue = keyValues[i];
          var value = keyValue["value"].eval(self, locals);
          object[keyValue["key"]] = value;
        }
        return object;
      });

  Expression profiled(value, _perf, text) {
    if (value is FilterExpression) return value;
    var wrappedGetter = (s, [l]) =>
    _perf.time('angular.parser.getter', () => value.eval(s, l), text);
    var wrappedAssignFn = null;
    if (value.assign != null) {
      wrappedAssignFn = (s, v, [l]) =>
      _perf.time('angular.parser.assign',
          () => value.assign(s, v, l), text);
    }
    return new Expression(wrappedGetter, wrappedAssignFn);
  }

  Expression fromOperator(String op) =>
      new Expression((s, [l]) => OPERATORS[op](s, l, null, null));

  Expression getterSetter(key) =>
      new Expression(getter(key), setter(key));

  Expression value(v) =>
      new Expression((self, [locals]) => v);

  zero() => ZERO;

  FilterExpression filter(String filterName,
                         Expression leftHandSide,
                         List<Expression> parameters,
                         Function evalError) {
    var filterFn = _filters(filterName);
    return new FilterExpression(filterFn, leftHandSide, parameters);
  }
}

class FilterExpression extends Expression {
  final Function filterFn;
  final Expression leftHandSide;
  final List<Expression> parameters;

  FilterExpression(Function this.filterFn,
                   Expression this.leftHandSide,
                   List<Expression> this.parameters): super(null);

  get eval => _eval;

  dynamic _eval(self, [locals]) {
    var args = [leftHandSide.eval(self, locals)];
    for ( var i = 0; i < parameters.length; i++) {
      args.add(parameters[i].eval(self, locals));
    }
    return Function.apply(filterFn, args);
  }
}
part of angular.core.dom;

class Compiler {
  DirectiveMap directives;
  DirectiveSelector selector;
  Profiler _perf;

  Compiler(DirectiveMap this.directives, Profiler this._perf) {
    selector = directiveSelectorFactory(directives);
  }

  _compileBlock(NodeCursor domCursor, NodeCursor templateCursor,
               List<DirectiveRef> useExistingDirectiveRefs) {
    if (domCursor.nodeList().length == 0) return null;

    var directivePositions = null; // don't pre-create to create sparse tree and prevent GC pressure.
    var cursorAlreadyAdvanced;

    do {
      var declaredDirectiveRefs = useExistingDirectiveRefs == null
          ?  selector(domCursor.nodeList()[0])
          : useExistingDirectiveRefs;
      var children = NgAnnotation.COMPILE_CHILDREN;
      var childDirectivePositions = null;
      List<DirectiveRef> usableDirectiveRefs = null;

      cursorAlreadyAdvanced = false;

      for (var j = 0, jj = declaredDirectiveRefs.length; j < jj; j++) {
        DirectiveRef directiveRef = declaredDirectiveRefs[j];
        NgAnnotation annotation = directiveRef.annotation;
        var blockFactory = null;

        if (annotation.children != children &&
            children == NgAnnotation.COMPILE_CHILDREN) {
          children = annotation.children;
        }

        if (children == NgAnnotation.TRANSCLUDE_CHILDREN) {
          var remainingDirectives = declaredDirectiveRefs.sublist(j + 1);
          blockFactory = compileTransclusion(
              domCursor, templateCursor,
              directiveRef, remainingDirectives);

          j = jj; // stop processing further directives since they belong to transclusion;
        }
        if (usableDirectiveRefs == null) {
          usableDirectiveRefs = [];
        }
        directiveRef.blockFactory = blockFactory;
        usableDirectiveRefs.add(directiveRef);
      }

      if (children == NgAnnotation.COMPILE_CHILDREN && domCursor.descend()) {
        templateCursor.descend();

        childDirectivePositions = _compileBlock(domCursor, templateCursor, null);

        domCursor.ascend();
        templateCursor.ascend();
      }

      if (childDirectivePositions != null || usableDirectiveRefs != null) {
        if (directivePositions == null) directivePositions = [];
        var directiveOffsetIndex = templateCursor.index;

        directivePositions
            ..add(directiveOffsetIndex)
            ..add(usableDirectiveRefs)
            ..add(childDirectivePositions);
      }
    } while (templateCursor.microNext() && domCursor.microNext());

    return directivePositions;
  }

  BlockFactory compileTransclusion(
                      NodeCursor domCursor, NodeCursor templateCursor,
                      DirectiveRef directiveRef,
                      List<DirectiveRef> transcludedDirectiveRefs) {
    var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
    var blockFactory;
    var blocks;

    var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
    var domCursorIndex = domCursor.index;
    var directivePositions = _compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs);
    if (directivePositions == null) directivePositions = [];

    blockFactory = new BlockFactory(transcludeCursor.elements, directivePositions, _perf);
    domCursor.index = domCursorIndex;

    if (domCursor.isInstance()) {
      domCursor.insertAnchorBefore(anchorName);
      blocks = [blockFactory(domCursor.nodeList())];
      domCursor.macroNext();
      templateCursor.macroNext();
      while (domCursor.isValid() && domCursor.isInstance()) {
        blocks.add(blockFactory(domCursor.nodeList()));
        domCursor.macroNext();
        templateCursor.remove();
      }
    } else {
      domCursor.replaceWithAnchor(anchorName);
    }

    return blockFactory;
  }

  BlockFactory call(List<dom.Node> elements) => _perf.time('angular.compiler', () {
    List<dom.Node> domElements = elements;
    List<dom.Node> templateElements = cloneElements(domElements);
    var directivePositions = _compileBlock(
        new NodeCursor(domElements), new NodeCursor(templateElements),
        null);

    return new BlockFactory(templateElements,
        directivePositions == null ? [] : directivePositions, _perf);
  });
}
library angular.io;

typedef FsVisitor(String file);

/**
 * A simple mockabe wrapper around dart:io that can be used without introducing
 * direct dependencies on dart:io.
 */
abstract class IoService {

  String readAsStringSync(String filePath);

  void visitFs(String rootDir, FsVisitor visitor);
}
// 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.

/**
 * This contains internal implementation details of the date formatting code
 * which are exposed as public functions because they must be called by other
 * libraries in order to configure the source for the locale data. We don't want
 * them exposed as public API functions in the date formatting library, so they
 * are put in a separate library here. These are for internal use only. User
 * code should import one of the `date_symbol_data...` libraries and call the
 * `initializeDateFormatting` method exposed there.
 */

library date_format_internal;
import 'dart:async';
import 'intl_helpers.dart';
import '../date_symbols.dart';

/**
 * This holds the symbols to be used for date/time formatting, indexed
 * by locale. Note that it will be set differently during initialization,
 * depending on what implementation we are using. By default, it is initialized
 * to an instance of UninitializedLocaleData, so any attempt to use it will
 * result in an informative error message.
 */
var dateTimeSymbols =
    new UninitializedLocaleData('initializeDateFormatting(<locale>)',
        en_USSymbols);

/**
 * This holds the patterns used for date/time formatting, indexed
 * by locale. Note that it will be set differently during initialization,
 * depending on what implementation we are using. By default, it is initialized
 * to an instance of UninitializedLocaleData, so any attempt to use it will
 * result in an informative error message.
 */
var dateTimePatterns =
    new UninitializedLocaleData('initializeDateFormatting(<locale>)',
        en_USPatterns);

/**
 * Initialize the symbols dictionary. This should be passed a function that
 * creates and returns the symbol data. We take a function so that if
 * initializing the data is an expensive operation it need only be done once,
 * no matter how many times this method is called.
 */
void initializeDateSymbols(Function symbols) {
  if (dateTimeSymbols is UninitializedLocaleData) {
    dateTimeSymbols = symbols();
  }
}

/**
 * Initialize the patterns dictionary. This should be passed a function that
 * creates and returns the pattern data. We take a function so that if
 * initializing the data is an expensive operation it need only be done once,
 * no matter how many times this method is called.
 */
void initializeDatePatterns(Function patterns) {
  if (dateTimePatterns is UninitializedLocaleData) {
    dateTimePatterns = patterns();
  }
}

Future initializeIndividualLocaleDateFormatting(Function init) {
  return init(dateTimeSymbols, dateTimePatterns);
}
part of angular.core;

/**
 * Any uncaught exception in angular expressions is delegated to this service.
 * The default implementation logs exceptions into console.
 *
 * In your application it is expected that this service is overridden with
 * your implementation which can store the exception for later processing.
 */
class ExceptionHandler {

 /**
  * Delegate uncaught exception for central error handling.
  *
  * - [error] The error which was caught.
  * - [stack] The stacktrace.
  * - [reason] Optional contextual information for the error.
  */
  call(dynamic error, dynamic stack, [String reason = '']){
    print("$error\n$reason\nSTACKTRACE:\n$stack");
  }
}
part of angular.mock;

/**
 * Mock implementation of [ExceptionHandler] that rethrows exceptions.
 */
class RethrowExceptionHandler extends ExceptionHandler {
  call(error, stack, [reason]){
    throw "$error $reason \nORIGINAL STACKTRACE:\n $stack";
  }
}

class ExceptionWithStack {
  final dynamic error;
  final dynamic stack;
  ExceptionWithStack(dynamic this.error, dynamic this.stack);
  toString() => "$error\n$stack";
}

/**
 * Mock implementation of [ExceptionHandler] that logs all exceptions for
 * later processing.
 */
class LoggingExceptionHandler implements ExceptionHandler {
  /**
   * All exceptions are stored here for later examining.
   */
  final List<ExceptionWithStack> errors = [];

  call(error, stack, [reason]) {
    errors.add(new ExceptionWithStack(error, stack));
  }

  /**
   * This method throws an exception if the errors is not empty.
   * It is recommended that this method is called on test tear-down
   * to verify that all exceptions have been processed.
   */
  assertEmpty() {
    if (errors.length > 0) {
      throw new ArgumentError('Exception Logger not empty:\n$errors');
    }
  }
}
library angular.filter;

import 'dart:json';
import 'package:intl/intl.dart';
import 'package:di/di.dart';
import '../core/module.dart';
import '../core/parser/parser_library.dart';

part 'currency.dart';
part 'date.dart';
part 'filter.dart';
part 'json.dart';
part 'limit_to.dart';
part 'lowercase.dart';
part 'number.dart';
part 'order_by.dart';
part 'uppercase.dart';

class NgFilterModule extends Module {
  NgFilterModule() {
    type(CurrencyFilter);
    type(DateFilter);
    type(FilterFilter);
    type(JsonFilter);
    type(LimitToFilter);
    type(LowercaseFilter);
    type(NumberFilter);
    type(OrderByFilter);
    type(UppercaseFilter);
  }
}
part of angular.mock;

String depth = '';

ENTER(name) {
  dump('${depth}ENTER: $name');
  depth = depth +  '  ';
}

LEAVE(name) {
  depth = depth.substring(0, depth.length -2);
  dump('${depth}LEAVE: $name');
}

MARK(name) {
  dump('$depth$name');
}


dump([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]) {
  var log = [];
  if (p1 != null) log.add(STRINGIFY(p1));
  if (p2 != null) log.add(STRINGIFY(p2));
  if (p3 != null) log.add(STRINGIFY(p3));
  if (p4 != null) log.add(STRINGIFY(p4));
  if (p5 != null) log.add(STRINGIFY(p5));
  if (p6 != null) log.add(STRINGIFY(p6));
  if (p7 != null) log.add(STRINGIFY(p7));
  if (p8 != null) log.add(STRINGIFY(p8));
  if (p9 != null) log.add(STRINGIFY(p9));
  if (p10 != null) log.add(STRINGIFY(p10));
  js.scoped(() {
   (js.context as dynamic).console.log(log.join(', '));
  });
}

STRINGIFY(obj) {
  if (obj is List) {
    var out = [];
    obj.forEach((i) => out.add(STRINGIFY(i)));
    return '[${out.join(", ")}]';
  } else if (obj is Comment) {
    return '<!--${obj.text}-->';
  } else if (obj is Element) {
    return obj.outerHtml;
  } else if (obj is String) {
    return '"$obj"';
  } else {
    return obj.toString();
  }
}
part of angular.core;

String _startSymbol = '{{';
String _endSymbol = '}}';
num _startSymbolLength = _startSymbol.length;
num _endSymbolLength = _endSymbol.length;

/**
 * Compiles a string with markup into an interpolation function. This service
 * is used by the HTML [Compiler] service for data binding.
 *
 *
 *     var $interpolate = ...; // injected
 *     var exp = $interpolate('Hello {{name}}!');
 *     expect(exp({name:'Angular'}).toEqual('Hello Angular!');
 */
class Interpolate {
  Parser _parse;
  ExceptionHandler _exceptionHandler;

  Interpolate(Parser this._parse, ExceptionHandler this._exceptionHandler);

  /**
   * Compile markup text into interpolation function.
   *
   * - `text`: The markup text to interpolate in form `foo {{expr}} bar`.
   * - `mustHaveExpression`: if set to true then the interpolation string must
   *      have embedded expression in order to return an interpolation function.
   *      Strings with no embedded expression will return null for the
   *      interpolation function.
   */
  Expression call(String text, [bool mustHaveExpression = false]) {
    num startIndex;
    num endIndex;
    num index = 0;
    List chunks = [];
    num length = text.length;
    bool hasInterpolation = false;
    String exp;
    List concat = [];
    Expression fn;

    while(index < length) {
      if ( ((startIndex = text.indexOf(_startSymbol, index)) != -1) &&
           ((endIndex = text.indexOf(_endSymbol, startIndex + _startSymbolLength)) != -1) ) {
        if (index != startIndex) {
          chunks.add(text.substring(index, startIndex));
        }
        fn = _parse(exp = text.substring(startIndex + _startSymbolLength, endIndex));
        chunks.add(fn);
        fn.exp = exp;
        index = endIndex + _endSymbolLength;
        hasInterpolation = true;
      } else {
        // we did not find anything, so we have to add the remainder to the chunks array
        if (index != length) {
          chunks.add(text.substring(index));
        }
        index = length;
      }
    }

    if ((length = chunks.length) == 0) {
      // we added, nothing, must have been an empty string.
      chunks.add('');
      length = 1;
    }

    if (!mustHaveExpression  || hasInterpolation) {
      fn = new Expression((context, [locals]) {
        try {
          for(var i = 0, ii = length, chunk; i<ii; i++) {
            if ((chunk = chunks[i]) is Expression) {
              chunk = chunk.eval(context);
              if (chunk == null) {
                chunk = '';
              } else if (!(chunk is String)) {
                chunk = '$chunk';
              }
            }
            concat.add(chunk);
          }
          return concat.join('');
        } catch(err, s) {
          _exceptionHandler("\$interpolate error! Can't interpolate: $text\n$err", s);
        } finally {
          concat.length = 0;
        }
      });
      fn.exp = text;
      fn.parts = chunks;
      return fn;
    }
  }
}