text: /**
   * @license AngularJS v1.0.0rc4
   * (c) 2010-2012 AngularJS http://angularjs.org
   * License: MIT
   */
  (function(window, document, undefined) {
  'use strict';
  
  ////////////////////////////////////
  
  if (typeof document.getAttribute == $undefined)
    document.getAttribute = function() {};
  
  /**
   * @ngdoc function
   * @name angular.lowercase
   * @function
   *
   * @description Converts the specified string to lowercase.
   * @param {string} string String to be converted to lowercase.
   * @returns {string} Lowercased string.
   */
  var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
  
  
  /**
   * @ngdoc function
   * @name angular.uppercase
   * @function
   *
   * @description Converts the specified string to uppercase.
   * @param {string} string String to be converted to uppercase.
   * @returns {string} Uppercased string.
   */
  var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
  
  
  var manualLowercase = function(s) {
    return isString(s)
        ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);})
        : s;
  };
  var manualUppercase = function(s) {
    return isString(s)
        ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);})
        : s;
  };
  
  
  // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
  // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
  // with correct but slower alternatives.
  if ('i' !== 'I'.toLowerCase()) {
    lowercase = manualLowercase;
    uppercase = manualUppercase;
  }
  
  function fromCharCode(code) {return String.fromCharCode(code);}
  
  
  var $boolean          = 'boolean',
      $console          = 'console',
      $length           = 'length',
      $name             = 'name',
      $object           = 'object',
      $string           = 'string',
      $undefined        = 'undefined',
      Error             = window.Error,
      /** holds major version number for IE or NaN for real browsers */
      msie              = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
      jqLite,           // delay binding since jQuery could be loaded after us.
      jQuery,           // delay binding
      slice             = [].slice,
      push              = [].push,
      toString          = Object.prototype.toString,
  
      /** @name angular */
      angular           = window.angular || (window.angular = {}),
      angularModule,
      /** @name angular.module.ng */
      nodeName_,
      uid               = ['0', '0', '0'];
  
  /**
   * @ngdoc function
   * @name angular.forEach
   * @function
   *
   * @description
   * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
   * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
   * is the value of an object property or an array element and `key` is the object property key or
   * array element index. Specifying a `context` for the function is optional.
   *
   * Note: this function was previously known as `angular.foreach`.
   *
     <pre>
       var values = {name: 'misko', gender: 'male'};
       var log = [];
       angular.forEach(values, function(value, key){
         this.push(key + ': ' + value);
       }, log);
       expect(log).toEqual(['name: misko', 'gender:male']);
     </pre>
   *
   * @param {Object|Array} obj Object to iterate over.
   * @param {Function} iterator Iterator function.
   * @param {Object=} context Object to become context (`this`) for the iterator function.
   * @returns {Object|Array} Reference to `obj`.
   */
  function forEach(obj, iterator, context) {
    var key;
    if (obj) {
      if (isFunction(obj)){
        for (key in obj) {
          if (key != 'prototype' && key != $length && key != $name && obj.hasOwnProperty(key)) {
            iterator.call(context, obj[key], key);
          }
        }
      } else if (obj.forEach && obj.forEach !== forEach) {
        obj.forEach(iterator, context);
      } else if (isObject(obj) && isNumber(obj.length)) {
        for (key = 0; key < obj.length; key++)
          iterator.call(context, obj[key], key);
      } else {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            iterator.call(context, obj[key], key);
          }
        }
      }
    }
    return obj;
  }
  
  function sortedKeys(obj) {
    var keys = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        keys.push(key);
      }
    }
    return keys.sort();
  }
  
  function forEachSorted(obj, iterator, context) {
    var keys = sortedKeys(obj)
    for ( var i = 0; i < keys.length; i++) {
      iterator.call(context, obj[keys[i]], keys[i]);
    }
    return keys;
  }
  
  
  /**
   * when using forEach the params are value, key, but it is often useful to have key, value.
   * @param {function(string, *)} iteratorFn
   * @returns {function(*, string)}
   */
  function reverseParams(iteratorFn) {
    return function(value, key) { iteratorFn(key, value) };
  }
  
  /**
   * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
   * characters such as '012ABC'. The reason why we are not using simply a number counter is that
   * the number string gets longer over time, and it can also overflow, where as the the nextId
   * will grow much slower, it is a string, and it will never overflow.
   *
   * @returns an unique alpha-numeric string
   */
  function nextUid() {
    var index = uid.length;
    var digit;
  
    while(index) {
      index--;
      digit = uid[index].charCodeAt(0);
      if (digit == 57 /*'9'*/) {
        uid[index] = 'A';
        return uid.join('');
      }
      if (digit == 90  /*'Z'*/) {
        uid[index] = '0';
      } else {
        uid[index] = String.fromCharCode(digit + 1);
        return uid.join('');
      }
    }
    uid.unshift('0');
    return uid.join('');
  }
  
  /**
   * @ngdoc function
   * @name angular.extend
   * @function
   *
   * @description
   * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
   * to `dst`. You can specify multiple `src` objects.
   *
   * @param {Object} dst Destination object.
   * @param {...Object} src Source object(s).
   */
  function extend(dst) {
    forEach(arguments, function(obj){
      if (obj !== dst) {
        forEach(obj, function(value, key){
          dst[key] = value;
        });
      }
    });
    return dst;
  }
  
  function int(str) {
    return parseInt(str, 10);
  }
  
  
  function inherit(parent, extra) {
    return extend(new (extend(function() {}, {prototype:parent}))(), extra);
  }
  
  
  /**
   * @ngdoc function
   * @name angular.noop
   * @function
   *
   * @description
   * A function that performs no operations. This function can be useful when writing code in the
   * functional style.
     <pre>
       function foo(callback) {
         var result = calculateResult();
         (callback || angular.noop)(result);
       }
     </pre>
   */
  function noop() {}
  noop.$inject = [];
  
  
  /**
   * @ngdoc function
   * @name angular.identity
   * @function
   *
   * @description
   * A function that returns its first argument. This function is useful when writing code in the
   * functional style.
   *
     <pre>
       function transformer(transformationFn, value) {
         return (transformationFn || identity)(value);
       };
     </pre>
   */
  function identity($) {return $;}
  identity.$inject = [];
  
  
  function valueFn(value) {return function() {return value;};}
  
  /**
   * @ngdoc function
   * @name angular.isUndefined
   * @function
   *
   * @description
   * Determines if a reference is undefined.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is undefined.
   */
  function isUndefined(value){return typeof value == $undefined;}
  
  
  /**
   * @ngdoc function
   * @name angular.isDefined
   * @function
   *
   * @description
   * Determines if a reference is defined.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is defined.
   */
  function isDefined(value){return typeof value != $undefined;}
  
  
  /**
   * @ngdoc function
   * @name angular.isObject
   * @function
   *
   * @description
   * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
   * considered to be objects.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is an `Object` but not `null`.
   */
  function isObject(value){return value!=null && typeof value == $object;}
  
  
  /**
   * @ngdoc function
   * @name angular.isString
   * @function
   *
   * @description
   * Determines if a reference is a `String`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `String`.
   */
  function isString(value){return typeof value == $string;}
  
  
  /**
   * @ngdoc function
   * @name angular.isNumber
   * @function
   *
   * @description
   * Determines if a reference is a `Number`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Number`.
   */
  function isNumber(value){return typeof value == 'number';}
  
  
  /**
   * @ngdoc function
   * @name angular.isDate
   * @function
   *
   * @description
   * Determines if a value is a date.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Date`.
   */
  function isDate(value){
    return toString.apply(value) == '[object Date]';
  }
  
  
  /**
   * @ngdoc function
   * @name angular.isArray
   * @function
   *
   * @description
   * Determines if a reference is an `Array`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is an `Array`.
   */
  function isArray(value) {
    return toString.apply(value) == '[object Array]';
  }
  
  
  /**
   * @ngdoc function
   * @name angular.isFunction
   * @function
   *
   * @description
   * Determines if a reference is a `Function`.
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a `Function`.
   */
  function isFunction(value){return typeof value == 'function';}
  
  
  /**
   * Checks if `obj` is a window object.
   *
   * @private
   * @param {*} obj Object to check
   * @returns {boolean} True if `obj` is a window obj.
   */
  function isWindow(obj) {
    return obj && obj.document && obj.location && obj.alert && obj.setInterval;
  }
  
  
  function isScope(obj) {
    return obj && obj.$evalAsync && obj.$watch;
  }
  
  
  function isFile(obj) {
    return toString.apply(obj) === '[object File]';
  }
  
  
  function isBoolean(value) {return typeof value == $boolean;}
  function isTextNode(node) {return nodeName_(node) == '#text';}
  
  function trim(value) {
    return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
  }
  
  /**
   * @ngdoc function
   * @name angular.isElement
   * @function
   *
   * @description
   * Determines if a reference is a DOM element (or wrapped jQuery element).
   *
   * @param {*} value Reference to check.
   * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
   */
  function isElement(node) {
    return node &&
      (node.nodeName  // we are a direct element
      || (node.bind && node.find));  // we have a bind and find method part of jQuery API
  }
  
  /**
   * @param str 'key1,key2,...'
   * @returns {object} in the form of {key1:true, key2:true, ...}
   */
  function makeMap(str){
    var obj = {}, items = str.split(","), i;
    for ( i = 0; i < items.length; i++ )
      obj[ items[i] ] = true;
    return obj;
  }
  
  
  
  /**
   * HTML class which is the only class which can be used in ng-bind to inline HTML for security
   * reasons.
   *
   * @constructor
   * @param html raw (unsafe) html
   * @param {string=} option If set to 'usafe', get method will return raw (unsafe/unsanitized) html
   */
  function HTML(html, option) {
    this.html = html;
    this.get = lowercase(option) == 'unsafe'
      ? valueFn(html)
      : function htmlSanitize() {
          var buf = [];
          htmlParser(html, htmlSanitizeWriter(buf));
          return buf.join('');
        };
  }
  
  if (msie < 9) {
    nodeName_ = function(element) {
      element = element.nodeName ? element : element[0];
      return (element.scopeName && element.scopeName != 'HTML')
        ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
    };
  } else {
    nodeName_ = function(element) {
      return element.nodeName ? element.nodeName : element[0].nodeName;
    };
  }
  
  function isVisible(element) {
    var rect = element[0].getBoundingClientRect(),
        width = (rect.width || (rect.right||0 - rect.left||0)),
        height = (rect.height || (rect.bottom||0 - rect.top||0));
    return width>0 && height>0;
  }
  
  function map(obj, iterator, context) {
    var results = [];
    forEach(obj, function(value, index, list) {
      results.push(iterator.call(context, value, index, list));
    });
    return results;
  }
  
  
  /**
   * @description
   * Determines the number of elements in an array, the number of properties an object has, or
   * the length of a string.
   *
   * Note: This function is used to augment the Object type in Angular expressions. See
   * {@link angular.Object} for more information about Angular arrays.
   *
   * @param {Object|Array|string} obj Object, array, or string to inspect.
   * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
   * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
   */
  function size(obj, ownPropsOnly) {
    var size = 0, key;
  
    if (isArray(obj) || isString(obj)) {
      return obj.length;
    } else if (isObject(obj)){
      for (key in obj)
        if (!ownPropsOnly || obj.hasOwnProperty(key))
          size++;
    }
  
    return size;
  }
  
  
  function includes(array, obj) {
    return indexOf(array, obj) != -1;
  }
  
  function indexOf(array, obj) {
    if (array.indexOf) return array.indexOf(obj);
  
    for ( var i = 0; i < array.length; i++) {
      if (obj === array[i]) return i;
    }
    return -1;
  }
  
  function arrayRemove(array, value) {
    var index = indexOf(array, value);
    if (index >=0)
      array.splice(index, 1);
    return value;
  }
  
  function isLeafNode (node) {
    if (node) {
      switch (node.nodeName) {
      case "OPTION":
      case "PRE":
      case "TITLE":
        return true;
      }
    }
    return false;
  }
  
  /**
   * @ngdoc function
   * @name angular.copy
   * @function
   *
   * @description
   * Creates a deep copy of `source`, which should be an object or an array.
   *
   * * If no destination is supplied, a copy of the object or array is created.
   * * If a destination is provided, all of its elements (for array) or properties (for objects)
   *   are deleted and then all elements/properties from the source are copied to it.
   * * If  `source` is not an object or array, `source` is returned.
   *
   * Note: this function is used to augment the Object type in Angular expressions. See
   * {@link angular.module.ng.$filter} for more information about Angular arrays.
   *
   * @param {*} source The source that will be used to make a copy.
   *                   Can be any type, including primitives, `null`, and `undefined`.
   * @param {(Object|Array)=} destination Destination into which the source is copied. If
   *     provided, must be of the same type as `source`.
   * @returns {*} The copy or updated `destination`, if `destination` was specified.
   */
  function copy(source, destination){
    if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
    if (!destination) {
      destination = source;
      if (source) {
        if (isArray(source)) {
          destination = copy(source, []);
        } else if (isDate(source)) {
          destination = new Date(source.getTime());
        } else if (isObject(source)) {
          destination = copy(source, {});
        }
      }
    } else {
      if (source === destination) throw Error("Can't copy equivalent objects or arrays");
      if (isArray(source)) {
        while(destination.length) {
          destination.pop();
        }
        for ( var i = 0; i < source.length; i++) {
          destination.push(copy(source[i]));
        }
      } else {
        forEach(destination, function(value, key){
          delete destination[key];
        });
        for ( var key in source) {
          destination[key] = copy(source[key]);
        }
      }
    }
    return destination;
  }
  
  /**
   * Create a shallow copy of an object
   */
  function shallowCopy(src, dst) {
    dst = dst || {};
  
    for(var key in src) {
      if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
        dst[key] = src[key];
      }
    }
  
    return dst;
  }
  
  
  /**
   * @ngdoc function
   * @name angular.equals
   * @function
   *
   * @description
   * Determines if two objects or two values are equivalent. Supports value types, arrays and
   * objects.
   *
   * Two objects or values are considered equivalent if at least one of the following is true:
   *
   * * Both objects or values pass `===` comparison.
   * * Both objects or values are of the same type and all of their properties pass `===` comparison.
   * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
   *
   * During a property comparision, properties of `function` type and properties with names
   * that begin with `$` are ignored.
   *
   * Scope and DOMWindow objects are being compared only be identify (`===`).
   *
   * @param {*} o1 Object or value to compare.
   * @param {*} o2 Object or value to compare.
   * @returns {boolean} True if arguments are equal.
   */
  function equals(o1, o2) {
    if (o1 === o2) return true;
    if (o1 === null || o2 === null) return false;
    if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
    var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
    if (t1 == t2) {
      if (t1 == 'object') {
        if (isArray(o1)) {
          if ((length = o1.length) == o2.length) {
            for(key=0; key<length; key++) {
              if (!equals(o1[key], o2[key])) return false;
            }
            return true;
          }
        } else if (isDate(o1)) {
          return isDate(o2) && o1.getTime() == o2.getTime();
        } else {
          if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
          keySet = {};
          for(key in o1) {
            if (key.charAt(0) !== '$' && !isFunction(o1[key]) && !equals(o1[key], o2[key])) {
              return false;
            }
            keySet[key] = true;
          }
          for(key in o2) {
            if (!keySet[key] && key.charAt(0) !== '$' && !isFunction(o2[key])) return false;
          }
          return true;
        }
      }
    }
    return false;
  }
  
  function setHtml(node, html) {
    if (isLeafNode(node)) {
      if (msie) {
        node.innerText = html;
      } else {
        node.textContent = html;
      }
    } else {
      node.innerHTML = html;
    }
  }
  
  function concat(array1, array2, index) {
    return array1.concat(slice.call(array2, index));
  }
  
  function sliceArgs(args, startIndex) {
    return slice.call(args, startIndex || 0);
  }
  
  
  /**
   * @ngdoc function
   * @name angular.bind
   * @function
   *
   * @description
   * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
   * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also
   * known as [function currying](http://en.wikipedia.org/wiki/Currying).
   *
   * @param {Object} self Context which `fn` should be evaluated in.
   * @param {function()} fn Function to be bound.
   * @param {...*} args Optional arguments to be prebound to the `fn` function call.
   * @returns {function()} Function that wraps the `fn` with all the specified bindings.
   */
  function bind(self, fn) {
    var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
    if (isFunction(fn) && !(fn instanceof RegExp)) {
      return curryArgs.length
        ? function() {
            return arguments.length
              ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
              : fn.apply(self, curryArgs);
          }
        : function() {
            return arguments.length
              ? fn.apply(self, arguments)
              : fn.call(self);
          };
    } else {
      // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
      return fn;
    }
  }
  
  
  function toJsonReplacer(key, value) {
    var val = value;
  
    if (/^\$+/.test(key)) {
      val = undefined;
    } else if (isWindow(value)) {
      val = '$WINDOW';
    } else if (value &&  document === value) {
      val = '$DOCUMENT';
    } else if (isScope(value)) {
      val = '$SCOPE';
    }
  
    return val;
  };
  
  
  /**
   * @ngdoc function
   * @name angular.toJson
   * @function
   *
   * @description
   * Serializes input into a JSON-formatted string.
   *
   * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
   * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
   * @returns {string} Jsonified string representing `obj`.
   */
  function toJson(obj, pretty) {
    return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
  }
  
  
  /**
   * @ngdoc function
   * @name angular.fromJson
   * @function
   *
   * @description
   * Deserializes a JSON string.
   *
   * @param {string} json JSON string to deserialize.
   * @returns {Object|Array|Date|string|number} Deserialized thingy.
   */
  function fromJson(json) {
    return isString(json)
        ? JSON.parse(json)
        : json;
  }
  
  
  function toBoolean(value) {
    if (value && value.length !== 0) {
      var v = lowercase("" + value);
      value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
    } else {
      value = false;
    }
    return value;
  }
  
  /**
   * @returns {string} Returns the string representation of the element.
   */
  function startingTag(element) {
    element = jqLite(element).clone();
    try {
      // turns out IE does not let you set .html() on elements which
      // are not allowed to have children. So we just ignore it.
      element.html('');
    } catch(e) {};
    return jqLite('<div>').append(element).html().match(/^(<[^>]+>)/)[1];
  }
  
  
  /////////////////////////////////////////////////
  
  /**
   * Parses an escaped url query string into key-value pairs.
   * @returns Object.<(string|boolean)>
   */
  function parseKeyValue(/**string*/keyValue) {
    var obj = {}, key_value, key;
    forEach((keyValue || "").split('&'), function(keyValue){
      if (keyValue) {
        key_value = keyValue.split('=');
        key = decodeURIComponent(key_value[0]);
        obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
      }
    });
    return obj;
  }
  
  function toKeyValue(obj) {
    var parts = [];
    forEach(obj, function(value, key) {
      parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
    });
    return parts.length ? parts.join('&') : '';
  }
  
  
  /**
   * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
   * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
   * segments:
   *    segment       = *pchar
   *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
   *    pct-encoded   = "%" HEXDIG HEXDIG
   *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
   *                     / "*" / "+" / "," / ";" / "="
   */
  function encodeUriSegment(val) {
    return encodeUriQuery(val, true).
               replace(/%26/gi, '&').
               replace(/%3D/gi, '=').
               replace(/%2B/gi, '+');
  }
  
  
  /**
   * This method is intended for encoding *key* or *value* parts of query component. We need a custom
   * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
   * encoded per http://tools.ietf.org/html/rfc3986:
   *    query       = *( pchar / "/" / "?" )
   *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
   *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   *    pct-encoded   = "%" HEXDIG HEXDIG
   *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
   *                     / "*" / "+" / "," / ";" / "="
   */
  function encodeUriQuery(val, pctEncodeSpaces) {
    return encodeURIComponent(val).
               replace(/%40/gi, '@').
               replace(/%3A/gi, ':').
               replace(/%24/g, '$').
               replace(/%2C/gi, ',').
               replace((pctEncodeSpaces ? null : /%20/g), '+');
  }
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-app
   *
   * @element ANY
   * @param {angular.Module} ng-app on optional application
   *   {@link angular.module module} name to load.
   *
   * @description
   *
   * Use this directive to auto-bootstrap on application. Only
   * one directive can be used per HTML document. The directive
   * designates the root of the application and is typically placed
   * ot the root of the page.
   *
   * In the example below if the `ng-app` directive would not be placed
   * on the `html` element then the document would not be compiled
   * and the `{{ 1+2 }}` would not be resolved to `3`.
   *
   * `ng-app` is the easiest way to bootstrap an application.
   *
   <doc:example>
     <doc:source>
      I can add: 1 + 2 =  {{ 1+2 }}
     </doc:source>
   </doc:example>
   *
   */
  function angularInit(element, bootstrap) {
    var elements = [element],
        appElement,
        module,
        names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
        NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
  
    function append(element) {
      element && elements.push(element);
    }
  
    forEach(names, function(name) {
      names[name] = true;
      append(document.getElementById(name));
      name = name.replace(':', '\\:');
      if (element.querySelectorAll) {
        forEach(element.querySelectorAll('.' + name), append);
        forEach(element.querySelectorAll('.' + name + '\\:'), append);
        forEach(element.querySelectorAll('[' + name + ']'), append);
      };
    });
  
    forEach(elements, function(element) {
      if (!appElement) {
        var className = ' ' + element.className + ' ';
        var match = NG_APP_CLASS_REGEXP.exec(className);
        if (match) {
          appElement = element;
          module = (match[2] || '').replace(/\s+/g, ',');
        } else {
          forEach(element.attributes, function(attr) {
            if (!appElement && names[attr.name]) {
              appElement = element;
              module = attr.value;
            }
          });
        }
      }
    });
    if (appElement) {
      bootstrap(appElement, module ? [module] : []);
    }
  }
  
  /**
   * @ngdoc function
   * @name angular.bootstrap
   * @description
   * Use this function to manually start up angular application.
   *
   * See: {@link guide/dev_guide.bootstrap.manual_bootstrap Bootstrap}
   *
   * @param {Element} element DOM element which is the root of angular application.
   * @param {Array<String,function>=} modules an array of module declarations. See: {@link angular.module modules}
   * @param {angular.module.auta.$injector} the injector;
   */
  function bootstrap(element, modules) {
    element = jqLite(element);
    modules = modules || [];
    modules.unshift('ng');
    var injector = createInjector(modules);
    injector.invoke(
      ['$rootScope', '$compile', '$injector', function(scope, compile, injector){
        scope.$apply(function() {
          element.data('$injector', injector);
          compile(element)(scope);
        });
      }]
    );
    return injector;
  }
  
  var SNAKE_CASE_REGEXP = /[A-Z]/g;
  function snake_case(name, separator){
    separator = separator || '_';
    return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
      return (pos ? separator : '') + letter.toLowerCase();
    });
  }
  
  function bindJQuery() {
    // bind to jQuery if present;
    jQuery = window.jQuery;
    // reset to jQuery or default to us.
    if (jQuery) {
      jqLite = jQuery;
      extend(jQuery.fn, {
        scope: JQLitePrototype.scope,
        controller: JQLitePrototype.controller,
        injector: JQLitePrototype.injector,
        inheritedData: JQLitePrototype.inheritedData
      });
      JQLitePatchJQueryRemove('remove', true);
      JQLitePatchJQueryRemove('empty');
      JQLitePatchJQueryRemove('html');
    } else {
      jqLite = JQLite;
    }
    angular.element = jqLite;
  }
  
  /**
   * throw error of the argument is falsy.
   */
  function assertArg(arg, name, reason) {
    if (!arg) {
      var error = new Error("Argument '" + (name||'?') + "' is " +
          (reason || "required"));
      throw error;
    }
    return arg;
  }
  
  function assertArgFn(arg, name, acceptArrayAnnotation) {
    if (acceptArrayAnnotation && isArray(arg)) {
        arg = arg[arg.length - 1];
    }
  
    assertArg(isFunction(arg), name, 'not a function, got ' +
        (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
    return arg;
  }
  
  /**
   * @ngdoc interface
   * @name angular.Module
   * @description
   *
   * Interface for configuring angular {@link angular.module modules}.
   */
  
  function setupModuleLoader(window) {
  
    function ensure(obj, name, factory) {
      return obj[name] || (obj[name] = factory());
    }
  
    return ensure(ensure(window, 'angular', Object), 'module', function() {
      /** @type {Object.<string, angular.Module>} */
      var modules = {};
  
      /**
       * @ngdoc function
       * @name angular.module
       * @description
       *
       * The `angular.module` is a global place for creating and registering Angular modules. All
       * modules (angular core or 3rd party) that should be available to an application must be
       * registered using this mechanism.
       *
       *
       * # Module
       *
       * A module is a collocation of services, directives, filters, and configure information. Module
       * is used to configure the {@link angular.module.AUTO.$injector $injector}.
       *
       * <pre>
       * // Create a new module
       * var myModule = angular.module('myModule', []);
       *
       * // register a new service
       * myModule.value('appName', 'MyCoolApp');
       *
       * // configure existing services inside initialization blocks.
       * myModule.config(function($locationProvider) {
       *   // Configure existing providers
       *   $locationProvider.hashPrefix('!');
       * });
       * </pre>
       *
       * Then you can create an injector and load your modules like this:
       *
       * <pre>
       * var injector = angular.injector(['ng', 'MyModule'])
       * </pre>
       *
       * However it's more likely that you'll just use
       * {@link angular.module.ng.$compileProvider.directive.ng-app ng-app} or
       * {@link angular.bootstrap} to simplify this process for you.
       *
       * @param {!string} name The name of the module to create or retrieve.
       * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
       *        the module is being retrieved for further configuration.
       * @param {Function} configFn Option configuration function for the module. Same as
       *        {@link angular.Module#config Module#config()}.
       * @returns {module} new module with the {@link angular.Module} api.
       */
      return function module(name, requires, configFn) {
        if (requires && modules.hasOwnProperty(name)) {
          modules[name] = null;
        }
        return ensure(modules, name, function() {
          if (!requires) {
            throw Error('No module: ' + name);
          }
  
          /** @type {!Array.<Array.<*>>} */
          var invokeQueue = [];
  
          /** @type {!Array.<Function>} */
          var runBlocks = [];
  
          var config = invokeLater('$injector', 'invoke');
  
          /** @type {angular.Module} */
          var moduleInstance = {
            // Private state
            _invokeQueue: invokeQueue,
            _runBlocks: runBlocks,
  
            /**
             * @ngdoc property
             * @name angular.Module#requires
             * @propertyOf angular.Module
             * @returns {Array.<string>} List of module names which must be loaded before this module.
             * @description
             * Holds the list of modules which the injector will load before the current module is loaded.
             */
            requires: requires,
  
            /**
             * @ngdoc property
             * @name angular.Module#name
             * @propertyOf angular.Module
             * @returns {string} Name of the module.
             * @description
             */
            name: name,
  
  
            /**
             * @ngdoc method
             * @name angular.Module#provider
             * @methodOf angular.Module
             * @param {string} name service name
             * @param {Function} providerType Construction function for creating new instance of the service.
             * @description
             * See {@link angular.module.AUTO.$provide#provider $provide.provider()}.
             */
            provider: invokeLater('$provide', 'provider'),
  
            /**
             * @ngdoc method
             * @name angular.Module#factory
             * @methodOf angular.Module
             * @param {string} name service name
             * @param {Function} providerFunction Function for creating new instance of the service.
             * @description
             * See {@link angular.module.AUTO.$provide#factory $provide.factory()}.
             */
            factory: invokeLater('$provide', 'factory'),
  
            /**
             * @ngdoc method
             * @name angular.Module#service
             * @methodOf angular.Module
             * @param {string} name service name
             * @param {Function} constructor A constructor function that will be instantiated.
             * @description
             * See {@link angular.module.AUTO.$provide#service $provide.service()}.
             */
            service: invokeLater('$provide', 'service'),
  
            /**
             * @ngdoc method
             * @name angular.Module#value
             * @methodOf angular.Module
             * @param {string} name service name
             * @param {*} object Service instance object.
             * @description
             * See {@link angular.module.AUTO.$provide#value $provide.value()}.
             */
            value: invokeLater('$provide', 'value'),
  
            /**
             * @ngdoc method
             * @name angular.Module#constant
             * @methodOf angular.Module
             * @param {string} name constant name
             * @param {*} object Constant value.
             * @description
             * Because the constant are fixed, they get applied before other provide methods.
             * See {@link angular.module.AUTO.$provide#constant $provide.constant()}.
             */
            constant: invokeLater('$provide', 'constant', 'unshift'),
  
            /**
             * @ngdoc method
             * @name angular.Module#filter
             * @methodOf angular.Module
             * @param {string} name Filter name.
             * @param {Function} filterFactory Factory function for creating new instance of filter.
             * @description
             * See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}.
             */
            filter: invokeLater('$filterProvider', 'register'),
  
            /**
             * @ngdoc method
             * @name angular.Module#controller
             * @methodOf angular.Module
             * @param {string} name Controller name.
             * @param {Function} constructor Controller constructor function.
             * @description
             * See {@link angular.module.ng.$controllerProvider#register $controllerProvider.register()}.
             */
            controller: invokeLater('$controllerProvider', 'register'),
  
            /**
             * @ngdoc method
             * @name angular.Module#directive
             * @methodOf angular.Module
             * @param {string} name directive name
             * @param {Function} directiveFactory Factory function for creating new instance of
             * directives.
             * @description
             * See {@link angular.module.ng.$compileProvider.directive $compileProvider.directive()}.
             */
            directive: invokeLater('$compileProvider', 'directive'),
  
            /**
             * @ngdoc method
             * @name angular.Module#config
             * @methodOf angular.Module
             * @param {Function} configFn Execute this function on module load. Useful for service
             *    configuration.
             * @description
             * Use this method to register work which needs to be performed on module loading.
             */
            config: config,
  
            /**
             * @ngdoc method
             * @name angular.Module#run
             * @methodOf angular.Module
             * @param {Function} initializationFn Execute this function after injector creation.
             *    Useful for application initialization.
             * @description
             * Use this method to register work which needs to be performed when the injector with
             * with the current module is finished loading.
             */
            run: function(block) {
              runBlocks.push(block);
              return this;
            }
          };
  
          if (configFn) {
            config(configFn);
          }
  
          return  moduleInstance;
  
          /**
           * @param {string} provider
           * @param {string} method
           * @param {String=} insertMethod
           * @returns {angular.Module}
           */
          function invokeLater(provider, method, insertMethod) {
            return function() {
              invokeQueue[insertMethod || 'push']([provider, method, arguments]);
              return moduleInstance;
            }
          }
        });
      };
    });
  
  }
  
  /**
   * @ngdoc property
   * @name angular.version
   * @description
   * An object that contains information about the current AngularJS version. This object has the
   * following properties:
   *
   * - `full` â€“ `{string}` â€“ Full version string, such as "0.9.18".
   * - `major` â€“ `{number}` â€“ Major version number, such as "0".
   * - `minor` â€“ `{number}` â€“ Minor version number, such as "9".
   * - `dot` â€“ `{number}` â€“ Dot version number, such as "18".
   * - `codeName` â€“ `{string}` â€“ Code name of the release, such as "jiggling-armfat".
   */
  var version = {
    full: '1.0.0rc4',    // all of these placeholder strings will be replaced by rake's
    major: 1,    // compile task
    minor: 0,
    dot: 0,
    codeName: 'insomnia-induction'
  };
  
  
  function publishExternalAPI(angular){
    extend(angular, {
      'bootstrap': bootstrap,
      'copy': copy,
      'extend': extend,
      'equals': equals,
      'element': jqLite,
      'forEach': forEach,
      'injector': createInjector,
      'noop':noop,
      'bind':bind,
      'toJson': toJson,
      'fromJson': fromJson,
      'identity':identity,
      'isUndefined': isUndefined,
      'isDefined': isDefined,
      'isString': isString,
      'isFunction': isFunction,
      'isObject': isObject,
      'isNumber': isNumber,
      'isElement': isElement,
      'isArray': isArray,
      'version': version,
      'isDate': isDate,
      'lowercase': lowercase,
      'uppercase': uppercase,
      'callbacks': {counter: 0}
    });
  
    angularModule = setupModuleLoader(window);
    try {
      angularModule('ngLocale');
    } catch (e) {
      angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
    }
  
    angularModule('ng', ['ngLocale'], ['$provide',
      function ngModule($provide) {
        $provide.provider('$compile', $CompileProvider).
          directive({
              a: htmlAnchorDirective,
              input: inputDirective,
              textarea: inputDirective,
              form: formDirective,
              script: scriptDirective,
              select: selectDirective,
              style: styleDirective,
              option: optionDirective,
              ngBind: ngBindDirective,
              ngBindHtml: ngBindHtmlDirective,
              ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
              ngBindTemplate: ngBindTemplateDirective,
              ngClass: ngClassDirective,
              ngClassEven: ngClassEvenDirective,
              ngClassOdd: ngClassOddDirective,
              ngCloak: ngCloakDirective,
              ngController: ngControllerDirective,
              ngForm: ngFormDirective,
              ngHide: ngHideDirective,
              ngInclude: ngIncludeDirective,
              ngInit: ngInitDirective,
              ngNonBindable: ngNonBindableDirective,
              ngPluralize: ngPluralizeDirective,
              ngRepeat: ngRepeatDirective,
              ngShow: ngShowDirective,
              ngSubmit: ngSubmitDirective,
              ngStyle: ngStyleDirective,
              ngSwitch: ngSwitchDirective,
              ngSwitchWhen: ngSwitchWhenDirective,
              ngSwitchDefault: ngSwitchDefaultDirective,
              ngOptions: ngOptionsDirective,
              ngView: ngViewDirective,
              ngTransclude: ngTranscludeDirective,
              ngModel: ngModelDirective,
              ngList: ngListDirective,
              ngChange: ngChangeDirective,
              required: requiredDirective,
              ngRequired: requiredDirective,
              ngValue: ngValueDirective
          }).
          directive(ngAttributeAliasDirectives).
          directive(ngEventDirectives);
        $provide.provider({
          $anchorScroll: $AnchorScrollProvider,
          $browser: $BrowserProvider,
          $cacheFactory: $CacheFactoryProvider,
          $controller: $ControllerProvider,
          $defer: $DeferProvider,
          $document: $DocumentProvider,
          $exceptionHandler: $ExceptionHandlerProvider,
          $filter: $FilterProvider,
          $interpolate: $InterpolateProvider,
          $http: $HttpProvider,
          $httpBackend: $HttpBackendProvider,
          $location: $LocationProvider,
          $log: $LogProvider,
          $parse: $ParseProvider,
          $route: $RouteProvider,
          $routeParams: $RouteParamsProvider,
          $rootScope: $RootScopeProvider,
          $q: $QProvider,
          $sanitize: $SanitizeProvider,
          $sniffer: $SnifferProvider,
          $templateCache: $TemplateCacheProvider,
          $window: $WindowProvider
        });
      }
    ]);
  };
  
  //////////////////////////////////
  //JQLite
  //////////////////////////////////
  
  /**
   * @ngdoc function
   * @name angular.element
   * @function
   *
   * @description
   * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
   * `angular.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
   * jQuery is available, or a function that wraps the element or string in Angular's jQuery lite
   * implementation (commonly referred to as jqLite).
   *
   * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
   * event fired.
   *
   * jqLite is a tiny, API-compatible subset of jQuery that allows
   * Angular to manipulate the DOM. jqLite implements only the most commonly needed functionality
   * within a very small footprint, so only a subset of the jQuery API - methods, arguments and
   * invocation styles - are supported.
   *
   * Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
   * raw DOM references.
   *
   * ## Angular's jQuery lite provides the following methods:
   *
   * - [addClass()](http://api.jquery.com/addClass/)
   * - [after()](http://api.jquery.com/after/)
   * - [append()](http://api.jquery.com/append/)
   * - [attr()](http://api.jquery.com/attr/)
   * - [bind()](http://api.jquery.com/bind/)
   * - [children()](http://api.jquery.com/children/)
   * - [clone()](http://api.jquery.com/clone/)
   * - [contents()](http://api.jquery.com/contents/)
   * - [css()](http://api.jquery.com/css/)
   * - [data()](http://api.jquery.com/data/)
   * - [eq()](http://api.jquery.com/eq/)
   * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
   * - [hasClass()](http://api.jquery.com/hasClass/)
   * - [html()](http://api.jquery.com/html/)
   * - [next()](http://api.jquery.com/next/)
   * - [parent()](http://api.jquery.com/parent/)
   * - [prepend()](http://api.jquery.com/prepend/)
   * - [prop()](http://api.jquery.com/prop/)
   * - [ready()](http://api.jquery.com/ready/)
   * - [remove()](http://api.jquery.com/remove/)
   * - [removeAttr()](http://api.jquery.com/removeAttr/)
   * - [removeClass()](http://api.jquery.com/removeClass/)
   * - [removeData()](http://api.jquery.com/removeData/)
   * - [replaceWith()](http://api.jquery.com/replaceWith/)
   * - [text()](http://api.jquery.com/text/)
   * - [toggleClass()](http://api.jquery.com/toggleClass/)
   * - [unbind()](http://api.jquery.com/unbind/)
   * - [val()](http://api.jquery.com/val/)
   * - [wrap()](http://api.jquery.com/wrap/)
   *
   * ## In addtion to the above, Angular privides an additional method to both jQuery and jQuery lite:
   *
   * - `controller(name)` - retrieves the controller of the current element or its parent. By default
   *   retrieves controller associated with the `ng-controller` directive. If `name` is provided as
   *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
   *   `'ngModel'`).
   * - `injector()` - retrieves the injector of the current element or its parent.
   * - `scope()` - retrieves the {@link api/angular.module.ng.$rootScope.Scope scope} of the current
   *   element or its parent.
   * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
   *   parent element is reached.
   *
   * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
   * @returns {Object} jQuery object.
   */
  
  var jqCache = {},
      jqName = 'ng-' + new Date().getTime(),
      jqId = 1,
      addEventListenerFn = (window.document.addEventListener
        ? function(element, type, fn) {element.addEventListener(type, fn, false);}
        : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
      removeEventListenerFn = (window.document.removeEventListener
        ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
        : function(element, type, fn) {element.detachEvent('on' + type, fn); });
  
  function jqNextId() { return (jqId++); }
  
  
  function getStyle(element) {
    var current = {}, style = element[0].style, value, name, i;
    if (typeof style.length == 'number') {
      for(i = 0; i < style.length; i++) {
        name = style[i];
        current[name] = style[name];
      }
    } else {
      for (name in style) {
        value = style[name];
        if (1*name != name && name != 'cssText' && value && typeof value == 'string' && value !='false')
          current[name] = value;
      }
    }
    return current;
  }
  
  
  var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  var MOZ_HACK_REGEXP = /^moz([A-Z])/;
  
  /**
   * Converts snake_case to camelCase.
   * Also there is special case for Moz prefix starting with upper case letter.
   * @param name Name to normalize
   */
  function camelCase(name) {
    return name.
      replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter;
      }).
      replace(MOZ_HACK_REGEXP, 'Moz$1');
  }
  
  /////////////////////////////////////////////
  // jQuery mutation patch
  //
  //  In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
  // $destroy event on all DOM nodes being removed.
  //
  /////////////////////////////////////////////
  
  function JQLitePatchJQueryRemove(name, dispatchThis) {
    var originalJqFn = jQuery.fn[name];
    originalJqFn = originalJqFn.$original || originalJqFn;
    removePatch.$original = originalJqFn;
    jQuery.fn[name] = removePatch;
  
    function removePatch() {
      var list = [this],
          fireEvent = dispatchThis,
          set, setIndex, setLength,
          element, childIndex, childLength, children,
          fns, data;
  
      while(list.length) {
        set = list.shift();
        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
          element = jqLite(set[setIndex]);
          if (fireEvent) {
            data = element.data('events');
            if ( (fns = data && data.$destroy) ) {
              forEach(fns, function(fn){
                fn.handler();
              });
            }
          } else {
            fireEvent = !fireEvent;
          }
          for(childIndex = 0, childLength = (children = element.children()).length;
              childIndex < childLength;
              childIndex++) {
            list.push(jQuery(children[childIndex]));
          }
        }
      }
      return originalJqFn.apply(this, arguments);
    }
  }
  
  /////////////////////////////////////////////
  function JQLite(element) {
    if (element instanceof JQLite) {
      return element;
    }
    if (!(this instanceof JQLite)) {
      if (isString(element) && element.charAt(0) != '<') {
        throw Error('selectors not implemented');
      }
      return new JQLite(element);
    }
  
    if (isString(element)) {
      var div = document.createElement('div');
      // Read about the NoScope elements here:
      // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
      div.innerHTML = '<div>&nbsp;</div>' + element; // IE insanity to make NoScope elements work!
      div.removeChild(div.firstChild); // remove the superfluous div
      JQLiteAddNodes(this, div.childNodes);
      this.remove(); // detach the elements from the temporary DOM div.
    } else {
      JQLiteAddNodes(this, element);
    }
  }
  
  function JQLiteClone(element) {
    return element.cloneNode(true);
  }
  
  function JQLiteDealoc(element){
    JQLiteRemoveData(element);
    for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
      JQLiteDealoc(children[i]);
    }
  }
  
  function JQLiteRemoveData(element) {
    var cacheId = element[jqName],
    cache = jqCache[cacheId];
    if (cache) {
      if (cache.bind) {
        forEach(cache.bind, function(fn, type){
          if (type == '$destroy') {
            fn({});
          } else {
            removeEventListenerFn(element, type, fn);
          }
        });
      }
      delete jqCache[cacheId];
      element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
    }
  }
  
  function JQLiteData(element, key, value) {
    var cacheId = element[jqName],
        cache = jqCache[cacheId || -1];
    if (isDefined(value)) {
      if (!cache) {
        element[jqName] = cacheId = jqNextId();
        cache = jqCache[cacheId] = {};
      }
      cache[key] = value;
    } else {
      return cache ? cache[key] : null;
    }
  }
  
  function JQLiteHasClass(element, selector) {
    return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
        indexOf( " " + selector + " " ) > -1);
  }
  
  function JQLiteRemoveClass(element, selector) {
    if (selector) {
      forEach(selector.split(' '), function(cssClass) {
        element.className = trim(
            (" " + element.className + " ")
            .replace(/[\n\t]/g, " ")
            .replace(" " + trim(cssClass) + " ", " ")
        );
      });
    }
  }
  
  function JQLiteAddClass(element, selector) {
    if (selector) {
      forEach(selector.split(' '), function(cssClass) {
        if (!JQLiteHasClass(element, cssClass)) {
          element.className = trim(element.className + ' ' + trim(cssClass));
        }
      });
    }
  }
  
  function JQLiteAddNodes(root, elements) {
    if (elements) {
      elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
        ? elements
        : [ elements ];
      for(var i=0; i < elements.length; i++) {
        root.push(elements[i]);
      }
    }
  }
  
  function JQLiteController(element, name) {
    return JQLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
  }
  
  function JQLiteInheritedData(element, name, value) {
    element = jqLite(element);
  
    // if element is the document object work with the html element instead
    // this makes $(document).scope() possible
    if(element[0].nodeType == 9) {
      element = element.find('html');
    }
  
    while (element.length) {
      if (value = element.data(name)) return value;
      element = element.parent();
    }
  }
  
  //////////////////////////////////////////
  // Functions which are declared directly.
  //////////////////////////////////////////
  var JQLitePrototype = JQLite.prototype = {
    ready: function(fn) {
      var fired = false;
  
      function trigger() {
        if (fired) return;
        fired = true;
        fn();
      }
  
      this.bind('DOMContentLoaded', trigger); // works for modern browsers and IE9
      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
      JQLite(window).bind('load', trigger); // fallback to window.onload for others
    },
    toString: function() {
      var value = [];
      forEach(this, function(e){ value.push('' + e);});
      return '[' + value.join(', ') + ']';
    },
  
    eq: function(index) {
        return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
    },
  
    length: 0,
    push: push,
    sort: [].sort,
    splice: [].splice
  };
  
  //////////////////////////////////////////
  // Functions iterating getter/setters.
  // these functions return self on setter and
  // value on get.
  //////////////////////////////////////////
  var BOOLEAN_ATTR = {};
  forEach('multiple,selected,checked,disabled,readOnly,required'.split(','), function(value) {
    BOOLEAN_ATTR[lowercase(value)] = value;
  });
  var BOOLEAN_ELEMENTS = {};
  forEach('input,select,option,textarea,button,form'.split(','), function(value) {
    BOOLEAN_ELEMENTS[uppercase(value)] = true;
  });
  
  function isBooleanAttr(element, name) {
    return BOOLEAN_ELEMENTS[element.nodeName] && BOOLEAN_ATTR[name.toLowerCase()];
  }
  
  forEach({
    data: JQLiteData,
    inheritedData: JQLiteInheritedData,
  
    scope: function(element) {
      return JQLiteInheritedData(element, '$scope');
    },
  
    controller: JQLiteController ,
  
    injector: function(element) {
      return JQLiteInheritedData(element, '$injector');
    },
  
    removeAttr: function(element,name) {
      element.removeAttribute(name);
    },
  
    hasClass: JQLiteHasClass,
  
    css: function(element, name, value) {
      name = camelCase(name);
  
      if (isDefined(value)) {
        element.style[name] = value;
      } else {
        var val;
  
        if (msie <= 8) {
          // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
          val = element.currentStyle && element.currentStyle[name];
          if (val === '') val = 'auto';
        }
  
        val = val || element.style[name];
  
        if (msie <= 8) {
          // jquery weirdness :-/
          val = (val === '') ? undefined : val;
        }
  
        return  val;
      }
    },
  
    attr: function(element, name, value){
      var lowercasedName = lowercase(name);
      if (BOOLEAN_ATTR[lowercasedName]) {
        if (isDefined(value)) {
          if (!!value) {
            element[name] = true;
            element.setAttribute(name, lowercasedName);
          } else {
            element[name] = false;
            element.removeAttribute(lowercasedName);
          }
        } else {
          return (element[name] ||
                   (element.attributes.getNamedItem(name)|| noop).specified)
                 ? lowercasedName
                 : undefined;
        }
      } else if (isDefined(value)) {
        element.setAttribute(name, value);
      } else if (element.getAttribute) {
        // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
        // some elements (e.g. Document) don't have get attribute, so return undefined
        var ret = element.getAttribute(name, 2);
        // normalize non-existing attributes to undefined (as jQuery)
        return ret === null ? undefined : ret;
      }
    },
  
    prop: function(element, name, value) {
      if (isDefined(value)) {
        element[name] = value;
      } else {
        return element[name];
      }
    },
  
    text: extend((msie < 9)
        ? function(element, value) {
          if (element.nodeType == 1 /** Element */) {
            if (isUndefined(value))
              return element.innerText;
            element.innerText = value;
          } else {
            if (isUndefined(value))
              return element.nodeValue;
            element.nodeValue = value;
          }
        }
        : function(element, value) {
          if (isUndefined(value)) {
            return element.textContent;
          }
          element.textContent = value;
        }, {$dv:''}),
  
    val: function(element, value) {
      if (isUndefined(value)) {
        return element.value;
      }
      element.value = value;
    },
  
    html: function(element, value) {
      if (isUndefined(value)) {
        return element.innerHTML;
      }
      for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
        JQLiteDealoc(childNodes[i]);
      }
      element.innerHTML = value;
    }
  }, function(fn, name){
    /**
     * Properties: writes return selection, reads return first value
     */
    JQLite.prototype[name] = function(arg1, arg2) {
      var i, key;
  
      // JQLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
      // in a way that survives minification.
      if (((fn.length == 2 && (fn !== JQLiteHasClass && fn !== JQLiteController)) ? arg1 : arg2) === undefined) {
        if (isObject(arg1)) {
          // we are a write, but the object properties are the key/values
          for(i=0; i < this.length; i++) {
            for (key in arg1) {
              fn(this[i], key, arg1[key]);
            }
          }
          // return self for chaining
          return this;
        } else {
          // we are a read, so read the first child.
          if (this.length)
            return fn(this[0], arg1, arg2);
        }
      } else {
        // we are a write, so apply to all children
        for(i=0; i < this.length; i++) {
          fn(this[i], arg1, arg2);
        }
        // return self for chaining
        return this;
      }
      return fn.$dv;
    };
  });
  
  function createEventHandler(element) {
    var eventHandler = function (event) {
      if (!event.preventDefault) {
        event.preventDefault = function() {
          event.returnValue = false; //ie
        };
      }
  
      if (!event.stopPropagation) {
        event.stopPropagation = function() {
          event.cancelBubble = true; //ie
        };
      }
  
      if (!event.target) {
        event.target = event.srcElement || document;
      }
  
      if (isUndefined(event.defaultPrevented)) {
        var prevent = event.preventDefault;
        event.preventDefault = function() {
          event.defaultPrevented = true;
          prevent.call(event);
        };
        event.defaultPrevented = false;
      }
  
      event.isDefaultPrevented = function() {
        return event.defaultPrevented;
      };
  
      forEach(eventHandler.fns, function(fn){
        fn.call(element, event);
      });
  
      // Remove monkey-patched methods (IE),
      // as they would cause memory leaks in IE8.
      if (msie < 8) {
        // IE7 does not allow to delete property on native object
        event.preventDefault = null;
        event.stopPropagation = null;
        event.isDefaultPrevented = null;
      } else {
        // It shouldn't affect normal browsers (native methods are defined on prototype).
        delete event.preventDefault;
        delete event.stopPropagation;
        delete event.isDefaultPrevented;
      }
    };
    eventHandler.fns = [];
    return eventHandler;
  };
  
  //////////////////////////////////////////
  // Functions iterating traversal.
  // These functions chain results into a single
  // selector.
  //////////////////////////////////////////
  forEach({
    removeData: JQLiteRemoveData,
  
    dealoc: JQLiteDealoc,
  
    bind: function bindFn(element, type, fn){
      var bind = JQLiteData(element, 'bind');
  
  
      if (!bind) JQLiteData(element, 'bind', bind = {});
      forEach(type.split(' '), function(type){
        var eventHandler = bind[type];
  
  
        if (!eventHandler) {
          if (type == 'mouseenter' || type == 'mouseleave') {
            var mouseenter = bind.mouseenter = createEventHandler(element);
            var mouseleave = bind.mouseleave = createEventHandler(element);
            var counter = 0;
  
  
            bindFn(element, 'mouseover', function(event) {
              counter++;
              if (counter == 1) {
                event.type = 'mouseenter';
                mouseenter(event);
              }
            });
            bindFn(element, 'mouseout', function(event) {
              counter --;
              if (counter == 0) {
                event.type = 'mouseleave';
                mouseleave(event);
              }
            });
            eventHandler = bind[type];
          } else {
            eventHandler = bind[type] = createEventHandler(element);
            addEventListenerFn(element, type, eventHandler);
          }
        }
        eventHandler.fns.push(fn);
      });
    },
  
    unbind: function(element, type, fn) {
      var bind = JQLiteData(element, 'bind');
      if (!bind) return; //no listeners registered
  
      if (isUndefined(type)) {
        forEach(bind, function(eventHandler, type) {
          removeEventListenerFn(element, type, eventHandler);
          delete bind[type];
        });
      } else {
        if (isUndefined(fn)) {
          removeEventListenerFn(element, type, bind[type]);
          delete bind[type];
        } else {
          arrayRemove(bind[type].fns, fn);
        }
      }
    },
  
    replaceWith: function(element, replaceNode) {
      var index, parent = element.parentNode;
      JQLiteDealoc(element);
      forEach(new JQLite(replaceNode), function(node){
        if (index) {
          parent.insertBefore(node, index.nextSibling);
        } else {
          parent.replaceChild(node, element);
        }
        index = node;
      });
    },
  
    children: function(element) {
      var children = [];
      forEach(element.childNodes, function(element){
        if (element.nodeName != '#text')
          children.push(element);
      });
      return children;
    },
  
    contents: function(element) {
      return element.childNodes;
    },
  
    append: function(element, node) {
      forEach(new JQLite(node), function(child){
        if (element.nodeType === 1)
          element.appendChild(child);
      });
    },
  
    prepend: function(element, node) {
      if (element.nodeType === 1) {
        var index = element.firstChild;
        forEach(new JQLite(node), function(child){
          if (index) {
            element.insertBefore(child, index);
          } else {
            element.appendChild(child);
            index = child;
          }
        });
      }
    },
  
    wrap: function(element, wrapNode) {
      wrapNode = jqLite(wrapNode)[0];
      var parent = element.parentNode;
      if (parent) {
        parent.replaceChild(wrapNode, element);
      }
      wrapNode.appendChild(element);
    },
  
    remove: function(element) {
      JQLiteDealoc(element);
      var parent = element.parentNode;
      if (parent) parent.removeChild(element);
    },
  
    after: function(element, newElement) {
      var index = element, parent = element.parentNode;
      forEach(new JQLite(newElement), function(node){
        parent.insertBefore(node, index.nextSibling);
        index = node;
      });
    },
  
    addClass: JQLiteAddClass,
    removeClass: JQLiteRemoveClass,
  
    toggleClass: function(element, selector, condition) {
      if (isUndefined(condition)) {
        condition = !JQLiteHasClass(element, selector);
      }
      (condition ? JQLiteAddClass : JQLiteRemoveClass)(element, selector);
    },
  
    parent: function(element) {
      var parent = element.parentNode;
      return parent && parent.nodeType !== 11 ? parent : null;
    },
  
    next: function(element) {
      return element.nextSibling;
    },
  
    find: function(element, selector) {
      return element.getElementsByTagName(selector);
    },
  
    clone: JQLiteClone
  }, function(fn, name){
    /**
     * chaining functions
     */
    JQLite.prototype[name] = function(arg1, arg2) {
      var value;
      for(var i=0; i < this.length; i++) {
        if (value == undefined) {
          value = fn(this[i], arg1, arg2);
          if (value !== undefined) {
            // any function which returns a value needs to be wrapped
            value = jqLite(value);
          }
        } else {
          JQLiteAddNodes(value, fn(this[i], arg1, arg2));
        }
      }
      return value == undefined ? this : value;
    };
  });
  
  /**
   * Computes a hash of an 'obj'.
   * Hash of a:
   *  string is string
   *  number is number as string
   *  object is either result of calling $$hashKey function on the object or uniquely generated id,
   *         that is also assigned to the $$hashKey property of the object.
   *
   * @param obj
   * @returns {string} hash string such that the same input will have the same hash string.
   *         The resulting string key is in 'type:hashKey' format.
   */
  function hashKey(obj) {
    var objType = typeof obj,
        key;
  
    if (objType == 'object' && obj !== null) {
      if (typeof (key = obj.$$hashKey) == 'function') {
        // must invoke on object to keep the right this
        key = obj.$$hashKey();
      } else if (key === undefined) {
        key = obj.$$hashKey = nextUid();
      }
    } else {
      key = obj;
    }
  
    return objType + ':' + key;
  }
  
  /**
   * HashMap which can use objects as keys
   */
  function HashMap(array){
    forEach(array, this.put, this);
  }
  HashMap.prototype = {
    /**
     * Store key value pair
     * @param key key to store can be any type
     * @param value value to store can be any type
     */
    put: function(key, value) {
      this[hashKey(key)] = value;
    },
  
    /**
     * @param key
     * @returns the value for the key
     */
    get: function(key) {
      return this[hashKey(key)];
    },
  
    /**
     * Remove the key/value pair
     * @param key
     */
    remove: function(key) {
      var value = this[key = hashKey(key)];
      delete this[key];
      return value;
    }
  };
  
  /**
   * A map where multiple values can be added to the same key such that they form a queue.
   * @returns {HashQueueMap}
   */
  function HashQueueMap() {}
  HashQueueMap.prototype = {
    /**
     * Same as array push, but using an array as the value for the hash
     */
    push: function(key, value) {
      var array = this[key = hashKey(key)];
      if (!array) {
        this[key] = [value];
      } else {
        array.push(value);
      }
    },
  
    /**
     * Same as array shift, but using an array as the value for the hash
     */
    shift: function(key) {
      var array = this[key = hashKey(key)];
      if (array) {
        if (array.length == 1) {
          delete this[key];
          return array[0];
        } else {
          return array.shift();
        }
      }
    }
  };
  
  /**
   * @ngdoc function
   * @name angular.injector
   * @function
   *
   * @description
   * Creates an injector function that can be used for retrieving services as well as for
   * dependency injection (see {@link guide/dev_guide.di dependency injection}).
   *
  
   * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
   *        {@link angular.module}. The `ng` module must be explicitly added.
   * @returns {function()} Injector function. See {@link angular.module.AUTO.$injector $injector}.
   *
   * @example
   * Typical usage
   * <pre>
   *   // create an injector
   *   var $injector = angular.injector(['ng']);
   *
   *   // use the injector to kick of your application
   *   // use the type inference to auto inject arguments, or use implicit injection
   *   $injector.invoke(function($rootScope, $compile, $document){
   *     $compile($document)($rootScope);
   *     $rootScope.$digest();
   *   });
   * </pre>
   */
  
  
  /**
   * @ngdoc overview
   * @name angular.module.AUTO
   * @description
   *
   * Implicit module which gets automatically added to each {@link angular.module.AUTO.$injector $injector}.
   */
  
  var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
  var FN_ARG_SPLIT = /,/;
  var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
  var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
  function inferInjectionArgs(fn) {
    assertArgFn(fn);
    if (!fn.$inject) {
      var args = fn.$inject = [];
      var fnText = fn.toString().replace(STRIP_COMMENTS, '');
      var argDecl = fnText.match(FN_ARGS);
      forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
        arg.replace(FN_ARG, function(all, underscore, name){
          args.push(name);
        });
      });
    }
    return fn.$inject;
  }
  
  ///////////////////////////////////////
  
  /**
   * @ngdoc object
   * @name angular.module.AUTO.$injector
   * @function
   *
   * @description
   *
   * `$injector` is used to retrieve object instances as defined by
   * {@link angular.module.AUTO.$provide provider}, instantiate types, invoke methods,
   * and load modules.
   *
   * The following always holds true:
   *
   * <pre>
   *   var $injector = angular.injector();
   *   expect($injector.get('$injector')).toBe($injector);
   *   expect($injector.invoke(function($injector){
   *     return $injector;
   *   }).toBe($injector);
   * </pre>
   *
   * # Injection Function Annotation
   *
   * JavaScript does not have annotations, and annotations are needed for dependency injection. The
   * following ways are all valid way of annotating function with injection arguments and are equivalent.
   *
   * <pre>
   *   // inferred (only works if code not minified/obfuscated)
   *   $inject.invoke(function(serviceA){});
   *
   *   // annotated
   *   function explicit(serviceA) {};
   *   explicit.$inject = ['serviceA'];
   *   $inject.invoke(explicit);
   *
   *   // inline
   *   $inject.invoke(['serviceA', function(serviceA){}]);
   * </pre>
   *
   * ## Inference
   *
   * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
   * parsed and the function arguments can be extracted. *NOTE:* This does not work with minfication, and obfuscation
   * tools since these tools change the argument names.
   *
   * ## `$inject` Annotation
   * By adding a `$inject` property onto a function the injection parameters can be specified.
   *
   * ## Inline
   * As an array of injection names, where the last item in the array is the function to call.
   */
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$injector#get
   * @methodOf angular.module.AUTO.$injector
   *
   * @description
   * Return an instance of the service.
   *
   * @param {string} name The name of the instance to retrieve.
   * @return {*} The instance.
   */
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$injector#invoke
   * @methodOf angular.module.AUTO.$injector
   *
   * @description
   * Invoke the method and supply the method arguments from the `$injector`.
   *
   * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
   * @param {Object=} self The `this` for the invoked method.
   * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
   *   the `$injector` is consulted.
   * @return the value returned by the invoked `fn` function.
   */
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$injector#instantiate
   * @methodOf angular.module.AUTO.$injector
   * @description
   * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
   * all of the arguments to the constructor function as specified by the constructor annotation.
   *
   * @param {function} Type Annotated constructor function.
   * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
   *   the `$injector` is consulted.
   * @return new instance of `Type`.
   */
  
  
  /**
   * @ngdoc object
   * @name angular.module.AUTO.$provide
   *
   * @description
   *
   * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
   * The providers share the same name as the instance they create with the `Provider` suffixed to them.
   *
   * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
   * a service. The Provider can have additional methods which would allow for configuration of the provider.
   *
   * <pre>
   *   function GreetProvider() {
   *     var salutation = 'Hello';
   *
   *     this.salutation = function(text) {
   *       salutation = text;
   *     };
   *
   *     this.$get = function() {
   *       return function (name) {
   *         return salutation + ' ' + name + '!';
   *       };
   *     };
   *   }
   *
   *   describe('Greeter', function(){
   *
   *     beforeEach(module(function($provide) {
   *       $provide.provider('greet', GreetProvider);
   *     });
   *
   *     it('should greet', inject(function(greet) {
   *       expect(greet('angular')).toEqual('Hello angular!');
   *     }));
   *
   *     it('should allow configuration of salutation', function() {
   *       module(function(greetProvider) {
   *         greetProvider.salutation('Ahoj');
   *       });
   *       inject(function(greet) {
   *         expect(greet('angular')).toEqual('Ahoj angular!');
   *       });
   *     )};
   *
   *   });
   * </pre>
   */
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#provider
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
   *
   * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
   * @param {(Object|function())} provider If the provider is:
   *
   *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
   *               {@link angular.module.AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
   *   - `Constructor`: a new instance of the provider will be created using
   *               {@link angular.module.AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
   *
   * @returns {Object} registered provider instance
   */
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#factory
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * A short hand for configuring services if only `$get` method is required.
   *
   * @param {string} name The name of the instance.
   * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
   * `$provide.provider(name, {$get: $getFn})`.
   * @returns {Object} registered provider instance
   */
  
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#service
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * A short hand for registering service of given class.
   *
   * @param {string} name The name of the instance.
   * @param {Function} constructor A class (constructor function) that will be instantiated.
   * @returns {Object} registered provider instance
   */
  
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#value
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * A short hand for configuring services if the `$get` method is a constant.
   *
   * @param {string} name The name of the instance.
   * @param {*} value The value.
   * @returns {Object} registered provider instance
   */
  
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#constant
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * A constant value, but unlike {@link angular.module.AUTO.$provide#value value} it can be injected
   * into configuration function (other modules) and it is not interceptable by
   * {@link angular.module.AUTO.$provide#decorator decorator}.
   *
   * @param {string} name The name of the constant.
   * @param {*} value The constant value.
   * @returns {Object} registered instance
   */
  
  
  /**
   * @ngdoc method
   * @name angular.module.AUTO.$provide#decorator
   * @methodOf angular.module.AUTO.$provide
   * @description
   *
   * Decoration of service, allows the decorator to intercept the service instance creation. The
   * returned instance may be the original instance, or a new instance which delegates to the
   * original instance.
   *
   * @param {string} name The name of the service to decorate.
   * @param {function()} decorator This function will be invoked when the service needs to be
   *    instanciated. The function is called using the {@link angular.module.AUTO.$injector#invoke
   *    injector.invoke} method and is therefore fully injectable. Local injection arguments:
   *
   *    * `$delegate` - The original service instance, which can be monkey patched, configured,
   *      decorated or delegated to.
   */
  
  
  function createInjector(modulesToLoad) {
    var INSTANTIATING = {},
        providerSuffix = 'Provider',
        path = [],
        loadedModules = new HashMap(),
        providerCache = {
          $provide: {
              provider: supportObject(provider),
              factory: supportObject(factory),
              service: supportObject(service),
              value: supportObject(value),
              constant: supportObject(constant),
              decorator: decorator
            }
        },
        providerInjector = createInternalInjector(providerCache, function() {
          throw Error("Unknown provider: " + path.join(' <- '));
        }),
        instanceCache = {},
        instanceInjector = (instanceCache.$injector =
            createInternalInjector(instanceCache, function(servicename) {
              var provider = providerInjector.get(servicename + providerSuffix);
              return instanceInjector.invoke(provider.$get, provider);
            }));
  
  
    forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
  
    return instanceInjector;
  
    ////////////////////////////////////
    // $provider
    ////////////////////////////////////
  
    function supportObject(delegate) {
      return function(key, value) {
        if (isObject(key)) {
          forEach(key, reverseParams(delegate));
        } else {
          return delegate(key, value);
        }
      }
    }
  
    function provider(name, provider_) {
      if (isFunction(provider_)) {
        provider_ = providerInjector.instantiate(provider_);
      }
      if (!provider_.$get) {
        throw Error('Provider ' + name + ' must define $get factory method.');
      }
      return providerCache[name + providerSuffix] = provider_;
    }
  
    function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
  
    function service(name, constructor) {
      return factory(name, ['$injector', function($injector) {
        return $injector.instantiate(constructor);
      }]);
    }
  
    function value(name, value) { return factory(name, valueFn(value)); }
  
    function constant(name, value) {
      providerCache[name] = value;
      instanceCache[name] = value;
    }
  
    function decorator(serviceName, decorFn) {
      var origProvider = providerInjector.get(serviceName + providerSuffix),
          orig$get = origProvider.$get;
  
      origProvider.$get = function() {
        var origInstance = instanceInjector.invoke(orig$get, origProvider);
        return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
      };
    }
  
    ////////////////////////////////////
    // Module Loading
    ////////////////////////////////////
    function loadModules(modulesToLoad){
      var runBlocks = [];
      forEach(modulesToLoad, function(module) {
        if (loadedModules.get(module)) return;
        loadedModules.put(module, true);
        if (isString(module)) {
          var moduleFn = angularModule(module);
          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
  
          try {
            for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
              var invokeArgs = invokeQueue[i],
                  provider = invokeArgs[0] == '$injector'
                      ? providerInjector
                      : providerInjector.get(invokeArgs[0]);
  
              provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
            }
          } catch (e) {
            if (e.message) e.message += ' from ' + module;
            throw e;
          }
        } else if (isFunction(module)) {
          try {
            runBlocks.push(providerInjector.invoke(module));
          } catch (e) {
            if (e.message) e.message += ' from ' + module;
            throw e;
          }
        } else if (isArray(module)) {
          try {
            runBlocks.push(providerInjector.invoke(module));
          } catch (e) {
            if (e.message) e.message += ' from ' + String(module[module.length - 1]);
            throw e;
          }
        } else {
          assertArgFn(module, 'module');
        }
      });
      return runBlocks;
    }
  
    ////////////////////////////////////
    // internal Injector
    ////////////////////////////////////
  
    function createInternalInjector(cache, factory) {
  
      function getService(serviceName) {
        if (typeof serviceName !== 'string') {
          throw Error('Service name expected');
        }
        if (cache.hasOwnProperty(serviceName)) {
          if (cache[serviceName] === INSTANTIATING) {
            throw Error('Circular dependency: ' + path.join(' <- '));
          }
          return cache[serviceName];
        } else {
          try {
            path.unshift(serviceName);
            cache[serviceName] = INSTANTIATING;
            return cache[serviceName] = factory(serviceName);
          } finally {
            path.shift();
          }
        }
      }
  
      function invoke(fn, self, locals){
        var args = [],
            $inject,
            length,
            key;
  
        if (typeof fn == 'function') {
          $inject = inferInjectionArgs(fn);
          length = $inject.length;
        } else {
          if (isArray(fn)) {
            $inject = fn;
            length = $inject.length - 1;
            fn = $inject[length];
          }
          assertArgFn(fn, 'fn');
        }
  
        for(var i = 0; i < length; i++) {
          key = $inject[i];
          args.push(
            locals && locals.hasOwnProperty(key)
            ? locals[key]
            : getService(key, path)
          );
        }
  
        // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
        switch (self ? -1 : args.length) {
          case  0: return fn();
          case  1: return fn(args[0]);
          case  2: return fn(args[0], args[1]);
          case  3: return fn(args[0], args[1], args[2]);
          case  4: return fn(args[0], args[1], args[2], args[3]);
          case  5: return fn(args[0], args[1], args[2], args[3], args[4]);
          case  6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
          case  7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
          case  8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
          case  9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
          case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
          default: return fn.apply(self, args);
        }
      }
  
      function instantiate(Type, locals) {
        var Constructor = function() {},
            instance, returnedValue;
  
        Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
        instance = new Constructor();
        returnedValue = invoke(Type, instance, locals);
  
        return isObject(returnedValue) ? returnedValue : instance;
      }
  
      return {
        invoke: invoke,
        instantiate: instantiate,
        get: getService
      };
    }
  }
  /**
   * @ngdoc function
   * @name angular.module.ng.$anchorScroll
   * @requires $window
   * @requires $location
   * @requires $rootScope
   *
   * @description
   * When called, it checks current value of `$location.hash()` and scroll to related element,
   * according to rules specified in
   * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
   *
   * It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
   * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
   */
  function $AnchorScrollProvider() {
  
    var autoScrollingEnabled = true;
  
    this.disableAutoScrolling = function() {
      autoScrollingEnabled = false;
    };
  
    this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
      var document = $window.document;
  
      // helper function to get first anchor from a NodeList
      // can't use filter.filter, as it accepts only instances of Array
      // and IE can't convert NodeList to an array using [].slice
      // TODO(vojta): use filter if we change it to accept lists as well
      function getFirstAnchor(list) {
        var result = null;
        forEach(list, function(element) {
          if (!result && lowercase(element.nodeName) === 'a') result = element;
        });
        return result;
      }
  
      function scroll() {
        var hash = $location.hash(), elm;
  
        // empty hash, scroll to the top of the page
        if (!hash) $window.scrollTo(0, 0);
  
        // element with given id
        else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
  
        // first anchor with given name :-D
        else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
  
        // no element and hash == 'top', scroll to the top of the page
        else if (hash === 'top') $window.scrollTo(0, 0);
      }
  
      // does not scroll when user clicks on anchor link that is currently on
      // (no url change, no $locaiton.hash() change), browser native does scroll
      if (autoScrollingEnabled) {
        $rootScope.$watch(function() {return $location.hash();}, function() {
          $rootScope.$evalAsync(scroll);
        });
      }
  
      return scroll;
    }];
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$browser
   * @requires $log
   * @description
   * This object has two goals:
   *
   * - hide all the global state in the browser caused by the window object
   * - abstract away all the browser specific features and inconsistencies
   *
   * For tests we provide {@link angular.module.ngMock.$browser mock implementation} of the `$browser`
   * service, which can be used for convenient testing of the application without the interaction with
   * the real browser apis.
   */
  /**
   * @param {object} window The global window object.
   * @param {object} document jQuery wrapped document.
   * @param {object} body jQuery wrapped document.body.
   * @param {function()} XHR XMLHttpRequest constructor.
   * @param {object} $log console.log or an object with the same interface.
   * @param {object} $sniffer $sniffer service
   */
  function Browser(window, document, body, $log, $sniffer) {
    var self = this,
        rawDocument = document[0],
        location = window.location,
        history = window.history,
        setTimeout = window.setTimeout,
        clearTimeout = window.clearTimeout,
        pendingDeferIds = {};
  
    self.isMock = false;
  
    var outstandingRequestCount = 0;
    var outstandingRequestCallbacks = [];
  
    // TODO(vojta): remove this temporary api
    self.$$completeOutstandingRequest = completeOutstandingRequest;
    self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
  
    /**
     * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
     * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
     */
    function completeOutstandingRequest(fn) {
      try {
        fn.apply(null, sliceArgs(arguments, 1));
      } finally {
        outstandingRequestCount--;
        if (outstandingRequestCount === 0) {
          while(outstandingRequestCallbacks.length) {
            try {
              outstandingRequestCallbacks.pop()();
            } catch (e) {
              $log.error(e);
            }
          }
        }
      }
    }
  
    /**
     * @private
     * Note: this method is used only by scenario runner
     * TODO(vojta): prefix this method with $$ ?
     * @param {function()} callback Function that will be called when no outstanding request
     */
    self.notifyWhenNoOutstandingRequests = function(callback) {
      // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
      // at some deterministic time in respect to the test runner's actions. Leaving things up to the
      // regular poller would result in flaky tests.
      forEach(pollFns, function(pollFn){ pollFn(); });
  
      if (outstandingRequestCount === 0) {
        callback();
      } else {
        outstandingRequestCallbacks.push(callback);
      }
    };
  
    //////////////////////////////////////////////////////////////
    // Poll Watcher API
    //////////////////////////////////////////////////////////////
    var pollFns = [],
        pollTimeout;
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#addPollFn
     * @methodOf angular.module.ng.$browser
     *
     * @param {function()} fn Poll function to add
     *
     * @description
     * Adds a function to the list of functions that poller periodically executes,
     * and starts polling if not started yet.
     *
     * @returns {function()} the added function
     */
    self.addPollFn = function(fn) {
      if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
      pollFns.push(fn);
      return fn;
    };
  
    /**
     * @param {number} interval How often should browser call poll functions (ms)
     * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
     *
     * @description
     * Configures the poller to run in the specified intervals, using the specified
     * setTimeout fn and kicks it off.
     */
    function startPoller(interval, setTimeout) {
      (function check() {
        forEach(pollFns, function(pollFn){ pollFn(); });
        pollTimeout = setTimeout(check, interval);
      })();
    }
  
    //////////////////////////////////////////////////////////////
    // URL API
    //////////////////////////////////////////////////////////////
  
    var lastBrowserUrl = location.href;
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#url
     * @methodOf angular.module.ng.$browser
     *
     * @description
     * GETTER:
     * Without any argument, this method just returns current value of location.href.
     *
     * SETTER:
     * With at least one argument, this method sets url to new value.
     * If html5 history api supported, pushState/replaceState is used, otherwise
     * location.href/location.replace is used.
     * Returns its own instance to allow chaining
     *
     * NOTE: this api is intended for use only by the $location service. Please use the
     * {@link angular.module.ng.$location $location service} to change url.
     *
     * @param {string} url New url (when used as setter)
     * @param {boolean=} replace Should new url replace current history record ?
     */
    self.url = function(url, replace) {
      // setter
      if (url) {
        lastBrowserUrl = url;
        if ($sniffer.history) {
          if (replace) history.replaceState(null, '', url);
          else history.pushState(null, '', url);
        } else {
          if (replace) location.replace(url);
          else location.href = url;
        }
        return self;
      // getter
      } else {
        return location.href;
      }
    };
  
    var urlChangeListeners = [],
        urlChangeInit = false;
  
    function fireUrlChange() {
      if (lastBrowserUrl == self.url()) return;
  
      lastBrowserUrl = self.url();
      forEach(urlChangeListeners, function(listener) {
        listener(self.url());
      });
    }
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#onUrlChange
     * @methodOf angular.module.ng.$browser
     * @TODO(vojta): refactor to use node's syntax for events
     *
     * @description
     * Register callback function that will be called, when url changes.
     *
     * It's only called when the url is changed by outside of angular:
     * - user types different url into address bar
     * - user clicks on history (forward/back) button
     * - user clicks on a link
     *
     * It's not called when url is changed by $browser.url() method
     *
     * The listener gets called with new url as parameter.
     *
     * NOTE: this api is intended for use only by the $location service. Please use the
     * {@link angular.module.ng.$location $location service} to monitor url changes in angular apps.
     *
     * @param {function(string)} listener Listener function to be called when url changes.
     * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
     */
    self.onUrlChange = function(callback) {
      if (!urlChangeInit) {
        // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
        // don't fire popstate when user change the address bar and don't fire hashchange when url
        // changed by push/replaceState
  
        // html5 history api - popstate event
        if ($sniffer.history) jqLite(window).bind('popstate', fireUrlChange);
        // hashchange event
        if ($sniffer.hashchange) jqLite(window).bind('hashchange', fireUrlChange);
        // polling
        else self.addPollFn(fireUrlChange);
  
        urlChangeInit = true;
      }
  
      urlChangeListeners.push(callback);
      return callback;
    };
  
    //////////////////////////////////////////////////////////////
    // Cookies API
    //////////////////////////////////////////////////////////////
    var lastCookies = {};
    var lastCookieString = '';
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#cookies
     * @methodOf angular.module.ng.$browser
     *
     * @param {string=} name Cookie name
     * @param {string=} value Cokkie value
     *
     * @description
     * The cookies method provides a 'private' low level access to browser cookies.
     * It is not meant to be used directly, use the $cookie service instead.
     *
     * The return values vary depending on the arguments that the method was called with as follows:
     * <ul>
     *   <li>cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it</li>
     *   <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
     *   <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
     * </ul>
     *
     * @returns {Object} Hash of all cookies (if called without any parameter)
     */
    self.cookies = function(name, value) {
      var cookieLength, cookieArray, cookie, i, keyValue, index;
  
      if (name) {
        if (value === undefined) {
          rawDocument.cookie = escape(name) + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
        } else {
          if (isString(value)) {
            rawDocument.cookie = escape(name) + '=' + escape(value);
  
            cookieLength = name.length + value.length + 1;
            if (cookieLength > 4096) {
              $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
                cookieLength + " > 4096 bytes)!");
            }
            if (lastCookies.length > 20) {
              $log.warn("Cookie '"+ name +"' possibly not set or overflowed because too many cookies " +
                "were already set (" + lastCookies.length + " > 20 )");
            }
          }
        }
      } else {
        if (rawDocument.cookie !== lastCookieString) {
          lastCookieString = rawDocument.cookie;
          cookieArray = lastCookieString.split("; ");
          lastCookies = {};
  
          for (i = 0; i < cookieArray.length; i++) {
            cookie = cookieArray[i];
            index = cookie.indexOf('=');
            if (index > 0) { //ignore nameless cookies
              lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1));
            }
          }
        }
        return lastCookies;
      }
    };
  
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#defer
     * @methodOf angular.module.ng.$browser
     * @param {function()} fn A function, who's execution should be defered.
     * @param {number=} [delay=0] of milliseconds to defer the function execution.
     * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
     *
     * @description
     * Executes a fn asynchroniously via `setTimeout(fn, delay)`.
     *
     * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
     * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
     * via `$browser.defer.flush()`.
     *
     */
    self.defer = function(fn, delay) {
      var timeoutId;
      outstandingRequestCount++;
      timeoutId = setTimeout(function() {
        delete pendingDeferIds[timeoutId];
        completeOutstandingRequest(fn);
      }, delay || 0);
      pendingDeferIds[timeoutId] = true;
      return timeoutId;
    };
  
  
    /**
     * THIS DOC IS NOT VISIBLE because ngdocs can't process docs for foo#method.method
     *
     * @name angular.module.ng.$browser#defer.cancel
     * @methodOf angular.module.ng.$browser.defer
     *
     * @description
     * Cancels a defered task identified with `deferId`.
     *
     * @param {*} deferId Token returned by the `$browser.defer` function.
     * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
     */
    self.defer.cancel = function(deferId) {
      if (pendingDeferIds[deferId]) {
        delete pendingDeferIds[deferId];
        clearTimeout(deferId);
        completeOutstandingRequest(noop);
        return true;
      }
      return false;
    };
  
  
    //////////////////////////////////////////////////////////////
    // Misc API
    //////////////////////////////////////////////////////////////
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#addCss
     * @methodOf angular.module.ng.$browser
     *
     * @param {string} url Url to css file
     * @description
     * Adds a stylesheet tag to the head.
     */
    self.addCss = function(url) {
      var link = jqLite(rawDocument.createElement('link'));
      link.attr('rel', 'stylesheet');
      link.attr('type', 'text/css');
      link.attr('href', url);
      body.append(link);
    };
  
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$browser#addJs
     * @methodOf angular.module.ng.$browser
     *
     * @param {string} url Url to js file
     *
     * @description
     * Adds a script tag to the head.
     */
    self.addJs = function(url, done) {
      // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
      // - fetches local scripts via XHR and evals them
      // - adds and immediately removes script elements from the document
      var script = rawDocument.createElement('script');
  
      script.type = 'text/javascript';
      script.src = url;
  
      if (msie) {
        script.onreadystatechange = function() {
          /loaded|complete/.test(script.readyState) && done && done();
        };
      } else {
        if (done) script.onload = script.onerror = done;
      }
  
      body[0].appendChild(script);
  
      return script;
    };
  
    /**
     * Returns current <base href>
     * (always relative - without domain)
     *
     * @returns {string=}
     */
    self.baseHref = function() {
      var href = document.find('base').attr('href');
      return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
    };
  }
  
  function $BrowserProvider(){
    this.$get = ['$window', '$log', '$sniffer', '$document',
        function( $window,   $log,   $sniffer,   $document){
          return new Browser($window, $document, $document.find('body'), $log, $sniffer);
        }];
  }
  /**
   * @ngdoc object
   * @name angular.module.ng.$cacheFactory
   *
   * @description
   * Factory that constructs cache objects.
   *
   *
   * @param {string} cacheId Name or id of the newly created cache.
   * @param {object=} options Options object that specifies the cache behavior. Properties:
   *
   *   - `{number=}` `capacity` â€” turns the cache into LRU cache.
   *
   * @returns {object} Newly created cache object with the following set of methods:
   *
   * - `{object}` `info()` â€” Returns id, size, and options of cache.
   * - `{void}` `put({string} key, {*} value)` â€” Puts a new key-value pair into the cache.
   * - `{{*}} `get({string} key) â€” Returns cached value for `key` or undefined for cache miss.
   * - `{void}` `remove({string} key) â€” Removes a key-value pair from the cache.
   * - `{void}` `removeAll() â€” Removes all cached values.
   * - `{void}` `destroy() â€” Removes references to this cache from $cacheFactory.
   *
   */
  function $CacheFactoryProvider() {
  
    this.$get = function() {
      var caches = {};
  
      function cacheFactory(cacheId, options) {
        if (cacheId in caches) {
          throw Error('cacheId ' + cacheId + ' taken');
        }
  
        var size = 0,
            stats = extend({}, options, {id: cacheId}),
            data = {},
            capacity = (options && options.capacity) || Number.MAX_VALUE,
            lruHash = {},
            freshEnd = null,
            staleEnd = null;
  
        return caches[cacheId] = {
  
          put: function(key, value) {
            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
  
            refresh(lruEntry);
  
            if (isUndefined(value)) return;
            if (!(key in data)) size++;
            data[key] = value;
  
            if (size > capacity) {
              this.remove(staleEnd.key);
            }
          },
  
  
          get: function(key) {
            var lruEntry = lruHash[key];
  
            if (!lruEntry) return;
  
            refresh(lruEntry);
  
            return data[key];
          },
  
  
          remove: function(key) {
            var lruEntry = lruHash[key];
  
            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
            link(lruEntry.n,lruEntry.p);
  
            delete lruHash[key];
            delete data[key];
            size--;
          },
  
  
          removeAll: function() {
            data = {};
            size = 0;
            lruHash = {};
            freshEnd = staleEnd = null;
          },
  
  
          destroy: function() {
            data = null;
            stats = null;
            lruHash = null;
            delete caches[cacheId];
          },
  
  
          info: function() {
            return extend({}, stats, {size: size});
          }
        };
  
  
        /**
         * makes the `entry` the freshEnd of the LRU linked list
         */
        function refresh(entry) {
          if (entry != freshEnd) {
            if (!staleEnd) {
              staleEnd = entry;
            } else if (staleEnd == entry) {
              staleEnd = entry.n;
            }
  
            link(entry.n, entry.p);
            link(entry, freshEnd);
            freshEnd = entry;
            freshEnd.n = null;
          }
        }
  
  
        /**
         * bidirectionally links two entries of the LRU linked list
         */
        function link(nextEntry, prevEntry) {
          if (nextEntry != prevEntry) {
            if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
            if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
          }
        }
      }
  
  
      cacheFactory.info = function() {
        var info = {};
        forEach(caches, function(cache, cacheId) {
          info[cacheId] = cache.info();
        });
        return info;
      };
  
  
      cacheFactory.get = function(cacheId) {
        return caches[cacheId];
      };
  
  
      return cacheFactory;
    };
  }
  
  function $TemplateCacheProvider() {
    this.$get = ['$cacheFactory', function($cacheFactory) {
      return $cacheFactory('templates');
    }];
  }
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$compile
   * @function
   *
   * @description
   * Compiles a piece of HTML string or DOM into a template and produces a template function, which
   * can then be used to link {@link angular.module.ng.$rootScope.Scope scope} and the template together.
   *
   * The compilation is a process of walking the DOM tree and trying to match DOM elements to
   * {@link angular.module.ng.$compileProvider.directive directives}. For each match it
   * executes corresponding template function and collects the
   * instance functions into a single template function which is then returned.
   *
   * The template function can then be used once to produce the view or as it is the case with
   * {@link angular.module.ng.$compileProvider.directive.ng-repeat repeater} many-times, in which
   * case each call results in a view that is a DOM clone of the original template.
   *
   <doc:example module="compile">
     <doc:source>
      <script>
        // declare a new module, and inject the $compileProvider
        angular.module('compile', [], function($compileProvider) {
          // configure new 'compile' directive by passing a directive
          // factory function. The factory function injects the '$compile'
          $compileProvider.directive('compile', function($compile) {
            // directive factory creates a link function
            return function(scope, element, attrs) {
              scope.$watch(
                function(scope) {
                   // watch the 'compile' expression for changes
                  return scope.$eval(attrs.compile);
                },
                function(value) {
                  // when the 'compile' expression changes
                  // assign it into the current DOM
                  element.html(value);
  
                  // compile the new DOM and link it to the current
                  // scope.
                  // NOTE: we only compile .childNodes so that
                  // we don't get into infinite loop compiling ourselves
                  $compile(element.contents())(scope);
                }
              );
            };
          })
        });
  
        function Ctrl($scope) {
          $scope.name = 'Angular';
          $scope.html = 'Hello {{name}}';
        }
      </script>
      <div ng-controller="Ctrl">
        <input ng-model="name"> <br>
        <textarea ng-model="html"></textarea> <br>
        <div compile="html"></div>
      </div>
     </doc:source>
     <doc:scenario>
       it('should auto compile', function() {
         expect(element('div[compile]').text()).toBe('Hello Angular');
         input('html').enter('{{name}}!');
         expect(element('div[compile]').text()).toBe('Angular!');
       });
     </doc:scenario>
   </doc:example>
  
   *
   *
   * @param {string|DOMElement} element Element or HTML string to compile into a template function.
   * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
   * @param {number} maxPriority only apply directives lower then given priority (Only effects the
   *                 root element(s), not their children)
   * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
   * (a DOM element/tree) to a scope. Where:
   *
   *  * `scope` - A {@link angular.module.ng.$rootScope.Scope Scope} to bind to.
   *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
   *               `template` and call the `cloneAttachFn` function allowing the caller to attach the
   *               cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
   *               called as: <br> `cloneAttachFn(clonedElement, scope)` where:
   *
   *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
   *      * `scope` - is the current scope with which the linking function is working with.
   *
   * Calling the linking function returns the element of the template. It is either the original element
   * passed in, or the clone of the element if the `cloneAttachFn` is provided.
   *
   * After linking the view is not updateh until after a call to $digest which typically is done by
   * Angular automatically.
   *
   * If you need access to the bound view, there are two ways to do it:
   *
   * - If you are not asking the linking function to clone the template, create the DOM element(s)
   *   before you send them to the compiler and keep this reference around.
   *   <pre>
   *     var element = $compile('<p>{{total}}</p>')(scope);
   *   </pre>
   *
   * - if on the other hand, you need the element to be cloned, the view reference from the original
   *   example would not point to the clone, but rather to the original template that was cloned. In
   *   this case, you can access the clone via the cloneAttachFn:
   *   <pre>
   *     var templateHTML = angular.element('<p>{{total}}</p>'),
   *         scope = ....;
   *
   *     var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
   *       //attach the clone to DOM document at the right place
   *     });
   *
   *     //now we have reference to the cloned DOM via `clone`
   *   </pre>
   *
   *
   * For information on how the compiler works, see the
   * {@link guide/dev_guide.compiler Angular HTML Compiler} section of the Developer Guide.
   */
  
  
  $CompileProvider.$inject = ['$provide'];
  function $CompileProvider($provide) {
    var hasDirectives = {},
        Suffix = 'Directive',
        COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
        CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
        CONTENT_REGEXP = /\<\<content\>\>/i,
        HAS_ROOT_ELEMENT = /^\<[\s\S]*\>$/;
  
  
    this.directive = function registerDirective(name, directiveFactory) {
      if (isString(name)) {
        assertArg(directiveFactory, 'directive');
        if (!hasDirectives.hasOwnProperty(name)) {
          hasDirectives[name] = [];
          $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
            function($injector, $exceptionHandler) {
              var directives = [];
              forEach(hasDirectives[name], function(directiveFactory) {
                try {
                  var directive = $injector.invoke(directiveFactory);
                  if (isFunction(directive)) {
                    directive = { compile: valueFn(directive) };
                  } else if (!directive.compile && directive.link) {
                    directive.compile = valueFn(directive.link);
                  }
                  directive.priority = directive.priority || 0;
                  directive.name = directive.name || name;
                  directive.require = directive.require || (directive.controller && directive.name);
                  directive.restrict = directive.restrict || 'A';
                  directives.push(directive);
                } catch (e) {
                  $exceptionHandler(e);
                }
              });
              return directives;
            }]);
        }
        hasDirectives[name].push(directiveFactory);
      } else {
        forEach(name, reverseParams(registerDirective));
      }
      return this;
    };
  
  
    this.$get = [
              '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
              '$controller',
      function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
               $controller) {
  
      var LOCAL_MODE = {
        attribute: function(localName, mode, parentScope, scope, attr) {
          scope[localName] = attr[localName];
        },
  
        evaluate: function(localName, mode, parentScope, scope, attr) {
          scope[localName] = parentScope.$eval(attr[localName]);
        },
  
        bind: function(localName, mode, parentScope, scope, attr) {
          var getter = $interpolate(attr[localName]);
          scope.$watch(
            function() { return getter(parentScope); },
            function(v) { scope[localName] = v; }
          );
        },
  
        accessor: function(localName, mode, parentScope, scope, attr) {
          var getter = noop,
              setter = noop,
              exp = attr[localName];
  
          if (exp) {
            getter = $parse(exp);
            setter = getter.assign || function() {
              throw Error("Expression '" + exp + "' not assignable.");
            };
          }
  
          scope[localName] = function(value) {
            return arguments.length ? setter(parentScope, value) : getter(parentScope);
          };
        },
  
        expression: function(localName, mode, parentScope, scope, attr) {
          scope[localName] = function(locals) {
            $parse(attr[localName])(parentScope, locals);
          };
        }
      };
  
      var Attributes = function(element, attr) {
        this.$$element = element;
        this.$$observers = {};
        this.$attr = attr || {};
      };
  
      Attributes.prototype = {
        $normalize: directiveNormalize,
  
  
        /**
         * Set a normalized attribute on the element in a way such that all directives
         * can share the attribute. This function properly handles boolean attributes.
         * @param {string} key Normalized key. (ie ngAttribute)
         * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
         * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
         *     Defaults to true.
         * @param {string=} attrName Optional none normalized name. Defaults to key.
         */
        $set: function(key, value, writeAttr, attrName) {
          var booleanKey = isBooleanAttr(this.$$element[0], key.toLowerCase());
  
          if (booleanKey) {
            this.$$element.prop(key, value);
            attrName = booleanKey;
          }
  
          this[key] = value;
  
          // translate normalized key to actual key
          if (attrName) {
            this.$attr[key] = attrName;
          } else {
            attrName = this.$attr[key];
            if (!attrName) {
              this.$attr[key] = attrName = snake_case(key, '-');
            }
          }
  
          if (writeAttr !== false) {
            if (value === null || value === undefined) {
              this.$$element.removeAttr(attrName);
            } else {
              this.$$element.attr(attrName, value);
            }
          }
  
          // fire observers
          forEach(this.$$observers[key], function(fn) {
            try {
              fn(value);
            } catch (e) {
              $exceptionHandler(e);
            }
          });
        },
  
  
        /**
         * Observe an interpolated attribute.
         * The observer will never be called, if given attribute is not interpolated.
         *
         * @param {string} key Normalized key. (ie ngAttribute) .
         * @param {function(*)} fn Function that will be called whenever the attribute value changes.
         */
        $observe: function(key, fn) {
          // keep only observers for interpolated attrs
          if (this.$$observers[key]) {
            this.$$observers[key].push(fn);
          }
        }
      };
  
      return compile;
  
      //================================
  
      function compile(templateElement, transcludeFn, maxPriority) {
        if (!(templateElement instanceof jqLite)) {
          // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
          templateElement = jqLite(templateElement);
        }
        // We can not compile top level text elements since text nodes can be merged and we will
        // not be able to attach scope data to them, so we will wrap them in <span>
        forEach(templateElement, function(node, index){
          if (node.nodeType == 3 /* text node */) {
            templateElement[index] = jqLite(node).wrap('<span>').parent()[0];
          }
        });
        var linkingFn = compileNodes(templateElement, transcludeFn, templateElement, maxPriority);
        return function(scope, cloneConnectFn){
          assertArg(scope, 'scope');
          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
          // and sometimes changes the structure of the DOM.
          var element = cloneConnectFn
            ? JQLitePrototype.clone.call(templateElement) // IMPORTANT!!!
            : templateElement;
          safeAddClass(element.data('$scope', scope), 'ng-scope');
          if (cloneConnectFn) cloneConnectFn(element, scope);
          if (linkingFn) linkingFn(scope, element, element);
          return element;
        };
      }
  
      function wrongMode(localName, mode) {
        throw Error("Unsupported '" + mode + "' for '" + localName + "'.");
      }
  
      function safeAddClass(element, className) {
        try {
          element.addClass(className);
        } catch(e) {
          // ignore, since it means that we are trying to set class on
          // SVG element, where class name is read-only.
        }
      }
  
      /**
       * Compile function matches each node in nodeList against the directives. Once all directives
       * for a particular node are collected their compile functions are executed. The compile
       * functions return values - the linking functions - are combined into a composite linking
       * function, which is the a linking function for the node.
       *
       * @param {NodeList} nodeList an array of nodes to compile
       * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
       *        scope argument is auto-generated to the new child of the transcluded parent scope.
       * @param {DOMElement=} rootElement If the nodeList is the root of the compilation tree then the
       *        rootElement must be set the jqLite collection of the compile root. This is
       *        needed so that the jqLite collection items can be replaced with widgets.
       * @param {number=} max directive priority
       * @returns {?function} A composite linking function of all of the matched directives or null.
       */
      function compileNodes(nodeList, transcludeFn, rootElement, maxPriority) {
       var linkingFns = [],
           directiveLinkingFn, childLinkingFn, directives, attrs, linkingFnFound;
  
       for(var i = 0; i < nodeList.length; i++) {
         attrs = new Attributes();
  
         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
         directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
  
         directiveLinkingFn = (directives.length)
             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, rootElement)
             : null;
  
         childLinkingFn = (directiveLinkingFn && directiveLinkingFn.terminal)
             ? null
             : compileNodes(nodeList[i].childNodes,
                  directiveLinkingFn ? directiveLinkingFn.transclude : transcludeFn);
  
         linkingFns.push(directiveLinkingFn);
         linkingFns.push(childLinkingFn);
         linkingFnFound = (linkingFnFound || directiveLinkingFn || childLinkingFn);
       }
  
       // return a linking function if we have found anything, null otherwise
       return linkingFnFound ? linkingFn : null;
  
       /* nodesetLinkingFn */ function linkingFn(scope, nodeList, rootElement, boundTranscludeFn) {
         var childLinkingFn, directiveLinkingFn, node, childScope, childTransclusionFn;
  
         for(var i=0, n=0, ii=linkingFns.length; i<ii; n++) {
           node = nodeList[n];
           directiveLinkingFn = /* directiveLinkingFn */ linkingFns[i++];
           childLinkingFn = /* nodesetLinkingFn */ linkingFns[i++];
  
           if (directiveLinkingFn) {
             if (directiveLinkingFn.scope) {
               childScope = scope.$new(isObject(directiveLinkingFn.scope));
               jqLite(node).data('$scope', childScope);
             } else {
               childScope = scope;
             }
             childTransclusionFn = directiveLinkingFn.transclude;
             if (childTransclusionFn || (!boundTranscludeFn && transcludeFn)) {
               directiveLinkingFn(childLinkingFn, childScope, node, rootElement,
                   (function(transcludeFn) {
                     return function(cloneFn) {
                       var transcludeScope = scope.$new();
  
                       return transcludeFn(transcludeScope, cloneFn).
                           bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
                      };
                    })(childTransclusionFn || transcludeFn)
               );
             } else {
               directiveLinkingFn(childLinkingFn, childScope, node, undefined, boundTranscludeFn);
             }
           } else if (childLinkingFn) {
             childLinkingFn(scope, node.childNodes, undefined, boundTranscludeFn);
           }
         }
       }
     }
  
  
      /**
       * Looks for directives on the given node ands them to the directive collection which is sorted.
       *
       * @param node node to search
       * @param directives an array to which the directives are added to. This array is sorted before
       *        the function returns.
       * @param attrs the shared attrs object which is used to populate the normalized attributes.
       * @param {number=} max directive priority
       */
      function collectDirectives(node, directives, attrs, maxPriority) {
        var nodeType = node.nodeType,
            attrsMap = attrs.$attr,
            match,
            className;
  
        switch(nodeType) {
          case 1: /* Element */
            // use the node name: <directive>
            addDirective(directives,
                directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
  
            // iterate over the attributes
            for (var attr, name, nName, value, nAttrs = node.attributes,
                     j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
              attr = nAttrs[j];
              if (attr.specified) {
                name = attr.name;
                nName = directiveNormalize(name.toLowerCase());
                attrsMap[nName] = name;
                attrs[nName] = value = trim((msie && name == 'href')
                  ? decodeURIComponent(node.getAttribute(name, 2))
                  : attr.value);
                if (isBooleanAttr(node, nName)) {
                  attrs[nName] = true; // presence means true
                }
                addAttrInterpolateDirective(node, directives, value, nName)
                addDirective(directives, nName, 'A', maxPriority);
              }
            }
  
            // use class as directive
            className = node.className;
            if (isString(className)) {
              while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
                nName = directiveNormalize(match[2]);
                if (addDirective(directives, nName, 'C', maxPriority)) {
                  attrs[nName] = trim(match[3]);
                }
                className = className.substr(match.index + match[0].length);
              }
            }
            break;
          case 3: /* Text Node */
            addTextInterpolateDirective(directives, node.nodeValue);
            break;
          case 8: /* Comment */
            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
            if (match) {
              nName = directiveNormalize(match[1]);
              if (addDirective(directives, nName, 'M', maxPriority)) {
                attrs[nName] = trim(match[2]);
              }
            }
            break;
        }
  
        directives.sort(byPriority);
        return directives;
      }
  
  
      /**
       * Once the directives have been collected their compile functions is executed. This method
       * is responsible for inlining directive templates as well as terminating the application
       * of the directives if the terminal directive has been reached..
       *
       * @param {Array} directives Array of collected directives to execute their compile function.
       *        this needs to be pre-sorted by priority order.
       * @param {Node} templateNode The raw DOM node to apply the compile functions to
       * @param {Object} templateAttrs The shared attribute function
       * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
       *        scope argument is auto-generated to the new child of the transcluded parent scope.
       * @param {DOMElement} rootElement If we are working on the root of the compile tree then this
       *        argument has the root jqLite array so that we can replace widgets on it.
       * @returns linkingFn
       */
      function applyDirectivesToNode(directives, templateNode, templateAttrs, transcludeFn, rootElement) {
        var terminalPriority = -Number.MAX_VALUE,
            preLinkingFns = [],
            postLinkingFns = [],
            newScopeDirective = null,
            newIsolatedScopeDirective = null,
            templateDirective = null,
            delayedLinkingFn = null,
            element = templateAttrs.$$element = jqLite(templateNode),
            directive,
            directiveName,
            template,
            transcludeDirective,
            childTranscludeFn = transcludeFn,
            controllerDirectives,
            linkingFn,
            directiveValue;
  
        // executes all directives on the current element
        for(var i = 0, ii = directives.length; i < ii; i++) {
          directive = directives[i];
          template = undefined;
  
          if (terminalPriority > directive.priority) {
            break; // prevent further processing of directives
          }
  
          if (directiveValue = directive.scope) {
            assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, element);
            if (isObject(directiveValue)) {
              safeAddClass(element, 'ng-isolate-scope');
              newIsolatedScopeDirective = directive;
            }
            safeAddClass(element, 'ng-scope');
            newScopeDirective = newScopeDirective || directive;
          }
  
          directiveName = directive.name;
  
          if (directiveValue = directive.controller) {
            controllerDirectives = controllerDirectives || {};
            assertNoDuplicate("'" + directiveName + "' controller",
                controllerDirectives[directiveName], directive, element);
            controllerDirectives[directiveName] = directive;
          }
  
          if (directiveValue = directive.transclude) {
            assertNoDuplicate('transclusion', transcludeDirective, directive, element);
            transcludeDirective = directive;
            terminalPriority = directive.priority;
            if (directiveValue == 'element') {
              template = jqLite(templateNode);
              templateNode = (element = templateAttrs.$$element = jqLite(
                  '<!-- ' + directiveName + ': ' + templateAttrs[directiveName]  + ' -->'))[0];
              replaceWith(rootElement, jqLite(template[0]), templateNode);
              childTranscludeFn = compile(template, transcludeFn, terminalPriority);
            } else {
              template = jqLite(JQLiteClone(templateNode));
              element.html(''); // clear contents
              childTranscludeFn = compile(template.contents(), transcludeFn);
            }
          }
  
          if (directiveValue = directive.template) {
            assertNoDuplicate('template', templateDirective, directive, element);
            templateDirective = directive;
  
            // include the contents of the original element into the template and replace the element
            var content = directiveValue.replace(CONTENT_REGEXP, element.html());
            templateNode = jqLite(content)[0];
            if (directive.replace) {
              replaceWith(rootElement, element, templateNode);
  
              var newTemplateAttrs = {$attr: {}};
  
              // combine directives from the original node and from the template:
              // - take the array of directives for this element
              // - split it into two parts, those that were already applied and those that weren't
              // - collect directives from the template, add them to the second group and sort them
              // - append the second group with new directives to the first group
              directives = directives.concat(
                  collectDirectives(
                      templateNode,
                      directives.splice(i + 1, directives.length - (i + 1)),
                      newTemplateAttrs
                  )
              );
              mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
  
              ii = directives.length;
            } else {
              element.html(content);
            }
          }
  
          if (directive.templateUrl) {
            assertNoDuplicate('template', templateDirective, directive, element);
            templateDirective = directive;
            delayedLinkingFn = compileTemplateUrl(directives.splice(i, directives.length - i),
                /* directiveLinkingFn */ compositeLinkFn, element, templateAttrs, rootElement,
                directive.replace, childTranscludeFn);
            ii = directives.length;
          } else if (directive.compile) {
            try {
              linkingFn = directive.compile(element, templateAttrs, childTranscludeFn);
              if (isFunction(linkingFn)) {
                addLinkingFns(null, linkingFn);
              } else if (linkingFn) {
                addLinkingFns(linkingFn.pre, linkingFn.post);
              }
            } catch (e) {
              $exceptionHandler(e, startingTag(element));
            }
          }
  
          if (directive.terminal) {
            compositeLinkFn.terminal = true;
            terminalPriority = Math.max(terminalPriority, directive.priority);
          }
  
        }
  
        linkingFn = delayedLinkingFn || compositeLinkFn;
        linkingFn.scope = newScopeDirective && newScopeDirective.scope;
        linkingFn.transclude = transcludeDirective && childTranscludeFn;
  
        // if we have templateUrl, then we have to delay linking
        return linkingFn;
  
        ////////////////////
  
        function addLinkingFns(pre, post) {
          if (pre) {
            pre.require = directive.require;
            preLinkingFns.push(pre);
          }
          if (post) {
            post.require = directive.require;
            postLinkingFns.push(post);
          }
        }
  
  
        function getControllers(require, element) {
          var value, retrievalMethod = 'data', optional = false;
          if (isString(require)) {
            while((value = require.charAt(0)) == '^' || value == '?') {
              require = require.substr(1);
              if (value == '^') {
                retrievalMethod = 'inheritedData';
              }
              optional = optional || value == '?';
            }
            value = element[retrievalMethod]('$' + require + 'Controller');
            if (!value && !optional) {
              throw Error("No controller: " + require);
            }
            return value;
          } else if (isArray(require)) {
            value = [];
            forEach(require, function(require) {
              value.push(getControllers(require, element));
            });
          }
          return value;
        }
  
  
        /* directiveLinkingFn */
        function compositeLinkFn(/* nodesetLinkingFn */ childLinkingFn,
                                 scope, linkNode, rootElement, boundTranscludeFn) {
          var attrs, element, i, ii, linkingFn, controller;
  
          if (templateNode === linkNode) {
            attrs = templateAttrs;
          } else {
            attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
          }
          element = attrs.$$element;
  
          if (newScopeDirective && isObject(newScopeDirective.scope)) {
            forEach(newScopeDirective.scope, function(mode, name) {
              (LOCAL_MODE[mode] || wrongMode)(name, mode,
                  scope.$parent || scope, scope, attrs);
            });
          }
  
          if (controllerDirectives) {
            forEach(controllerDirectives, function(directive) {
              var locals = {
                $scope: scope,
                $element: element,
                $attrs: attrs,
                $transclude: boundTranscludeFn
              };
  
  
              forEach(directive.inject || {}, function(mode, name) {
                (LOCAL_MODE[mode] || wrongMode)(name, mode,
                    newScopeDirective ? scope.$parent || scope : scope, locals, attrs);
              });
  
              controller = directive.controller;
              if (controller == '@') {
                controller = attrs[directive.name];
              }
  
              element.data(
                  '$' + directive.name + 'Controller',
                  $controller(controller, locals));
            });
          }
  
          // PRELINKING
          for(i = 0, ii = preLinkingFns.length; i < ii; i++) {
            try {
              linkingFn = preLinkingFns[i];
              linkingFn(scope, element, attrs,
                  linkingFn.require && getControllers(linkingFn.require, element));
            } catch (e) {
              $exceptionHandler(e, startingTag(element));
            }
          }
  
          // RECURSION
          childLinkingFn && childLinkingFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
  
          // POSTLINKING
          for(i = 0, ii = postLinkingFns.length; i < ii; i++) {
            try {
              linkingFn = postLinkingFns[i];
              linkingFn(scope, element, attrs,
                  linkingFn.require && getControllers(linkingFn.require, element));
            } catch (e) {
              $exceptionHandler(e, startingTag(element));
            }
          }
        }
      }
  
  
      /**
       * looks up the directive and decorates it with exception handling and proper parameters. We
       * call this the boundDirective.
       *
       * @param {string} name name of the directive to look up.
       * @param {string} location The directive must be found in specific format.
       *   String containing any of theses characters:
       *
       *   * `E`: element name
       *   * `A': attribute
       *   * `C`: class
       *   * `M`: comment
       * @returns true if directive was added.
       */
      function addDirective(tDirectives, name, location, maxPriority) {
        var match = false;
        if (hasDirectives.hasOwnProperty(name)) {
          for(var directive, directives = $injector.get(name + Suffix),
              i=0, ii = directives.length; i<ii; i++) {
            try {
              directive = directives[i];
              if ( (maxPriority === undefined || maxPriority > directive.priority) &&
                   directive.restrict.indexOf(location) != -1) {
                tDirectives.push(directive);
                match = true;
              }
            } catch(e) { $exceptionHandler(e); }
          }
        }
        return match;
      }
  
  
      /**
       * When the element is replaced with HTML template then the new attributes
       * on the template need to be merged with the existing attributes in the DOM.
       * The desired effect is to have both of the attributes present.
       *
       * @param {object} dst destination attributes (original DOM)
       * @param {object} src source attributes (from the directive template)
       */
      function mergeTemplateAttributes(dst, src) {
        var srcAttr = src.$attr,
            dstAttr = dst.$attr,
            element = dst.$$element;
        // reapply the old attributes to the new element
        forEach(dst, function(value, key) {
          if (key.charAt(0) != '$') {
            if (src[key]) {
              value += (key === 'style' ? ';' : ' ') + src[key];
            }
            dst.$set(key, value, true, srcAttr[key]);
          }
        });
        // copy the new attributes on the old attrs object
        forEach(src, function(value, key) {
          if (key == 'class') {
            safeAddClass(element, value);
          } else if (key == 'style') {
            element.attr('style', element.attr('style') + ';' + value);
          } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
            dst[key] = value;
            dstAttr[key] = srcAttr[key];
          }
        });
      }
  
  
      function compileTemplateUrl(directives, /* directiveLinkingFn */ beforeWidgetLinkFn,
                                  tElement, tAttrs, rootElement, replace, transcludeFn) {
        var linkQueue = [],
            afterWidgetLinkFn,
            afterWidgetChildrenLinkFn,
            originalWidgetNode = tElement[0],
            asyncWidgetDirective = directives.shift(),
            // The fact that we have to copy and patch the directive seems wrong!
            syncWidgetDirective = extend({}, asyncWidgetDirective, {templateUrl:null, transclude:null}),
            html = tElement.html();
  
        tElement.html('');
  
        $http.get(asyncWidgetDirective.templateUrl, {cache: $templateCache}).
          success(function(content) {
            content = trim(content).replace(CONTENT_REGEXP, html);
            if (replace && !content.match(HAS_ROOT_ELEMENT)) {
              throw Error('Template must have exactly one root element: ' + content);
            }
  
            var templateNode, tempTemplateAttrs;
  
            if (replace) {
              tempTemplateAttrs = {$attr: {}};
              templateNode = jqLite(content)[0];
              replaceWith(rootElement, tElement, templateNode);
              collectDirectives(tElement[0], directives, tempTemplateAttrs);
              mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
            } else {
              templateNode = tElement[0];
              tElement.html(content);
            }
  
            directives.unshift(syncWidgetDirective);
            afterWidgetLinkFn = /* directiveLinkingFn */ applyDirectivesToNode(directives, tElement, tAttrs, transcludeFn);
            afterWidgetChildrenLinkFn = /* nodesetLinkingFn */ compileNodes(tElement.contents(), transcludeFn);
  
  
            while(linkQueue.length) {
              var controller = linkQueue.pop(),
                  linkRootElement = linkQueue.pop(),
                  cLinkNode = linkQueue.pop(),
                  scope = linkQueue.pop(),
                  node = templateNode;
  
              if (cLinkNode !== originalWidgetNode) {
                // it was cloned therefore we have to clone as well.
                node = JQLiteClone(templateNode);
                replaceWith(linkRootElement, jqLite(cLinkNode), node);
              }
              afterWidgetLinkFn(function() {
                beforeWidgetLinkFn(afterWidgetChildrenLinkFn, scope, node, rootElement, controller);
              }, scope, node, rootElement, controller);
            }
            linkQueue = null;
          }).
          error(function(response, code, headers, config) {
            throw Error('Failed to load template: ' + config.url);
          });
  
        return /* directiveLinkingFn */ function(ignoreChildLinkingFn, scope, node, rootElement,
                                                 controller) {
          if (linkQueue) {
            linkQueue.push(scope);
            linkQueue.push(node);
            linkQueue.push(rootElement);
            linkQueue.push(controller);
          } else {
            afterWidgetLinkFn(function() {
              beforeWidgetLinkFn(afterWidgetChildrenLinkFn, scope, node, rootElement, controller);
            }, scope, node, rootElement, controller);
          }
        };
      }
  
  
      /**
       * Sorting function for bound directives.
       */
      function byPriority(a, b) {
        return b.priority - a.priority;
      }
  
  
      function assertNoDuplicate(what, previousDirective, directive, element) {
        if (previousDirective) {
          throw Error('Multiple directives [' + previousDirective.name + ', ' +
            directive.name + '] asking for ' + what + ' on: ' +  startingTag(element));
        }
      }
  
  
      function addTextInterpolateDirective(directives, text) {
        var interpolateFn = $interpolate(text, true);
        if (interpolateFn) {
          directives.push({
            priority: 0,
            compile: valueFn(function(scope, node) {
              var parent = node.parent(),
                  bindings = parent.data('$binding') || [];
              bindings.push(interpolateFn);
              safeAddClass(parent.data('$binding', bindings), 'ng-binding');
              scope.$watch(interpolateFn, function(value) {
                node[0].nodeValue = value;
              });
            })
          });
        }
      }
  
  
      function addAttrInterpolateDirective(node, directives, value, name) {
        var interpolateFn = $interpolate(value, true);
  
  
        // no interpolation found -> ignore
        if (!interpolateFn) return;
  
        directives.push({
          priority: 100,
          compile: valueFn(function(scope, element, attr) {
            if (name === 'class') {
              // we need to interpolate classes again, in the case the element was replaced
              // and therefore the two class attrs got merged - we want to interpolate the result
              interpolateFn = $interpolate(attr[name], true);
            }
  
            // we define observers array only for interpolated attrs
            // and ignore observers for non interpolated attrs to save some memory
            attr.$$observers[name] = [];
            attr[name] = undefined;
            scope.$watch(interpolateFn, function(value) {
              attr.$set(name, value);
            });
          })
        });
      }
  
  
      /**
       * This is a special jqLite.replaceWith, which can replace items which
       * have no parents, provided that the containing jqLite collection is provided.
       *
       * @param {JqLite=} rootElement The root of the compile tree. Used so that we can replace nodes
       *    in the root of the tree.
       * @param {JqLite} element The jqLite element which we are going to replace. We keep the shell,
       *    but replace its DOM node reference.
       * @param {Node} newNode The new DOM node.
       */
      function replaceWith(rootElement, element, newNode) {
        var oldNode = element[0],
            parent = oldNode.parentNode,
            i, ii;
  
        if (rootElement) {
          for(i = 0, ii = rootElement.length; i<ii; i++) {
            if (rootElement[i] == oldNode) {
              rootElement[i] = newNode;
            }
          }
        }
        if (parent) {
          parent.replaceChild(newNode, oldNode);
        }
        element[0] = newNode;
      }
    }];
  }
  
  var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
  /**
   * Converts all accepted directives format into proper directive name.
   * All of these will become 'myDirective':
   *   my:DiRective
   *   my-directive
   *   x-my-directive
   *   data-my:directive
   *
   * Also there is special case for Moz prefix starting with upper case letter.
   * @param name Name to normalize
   */
  function directiveNormalize(name) {
    return camelCase(name.replace(PREFIX_REGEXP, ''));
  }
  
  
  
  /**
   * Closure compiler type information
   */
  
  function nodesetLinkingFn(
    /* angular.Scope */ scope,
    /* NodeList */ nodeList,
    /* Element */ rootElement,
    /* function(Function) */ boundTranscludeFn
  ){}
  
  function directiveLinkingFn(
    /* nodesetLinkingFn */ nodesetLinkingFn,
    /* angular.Scope */ scope,
    /* Node */ node,
    /* Element */ rootElement,
    /* function(Function) */ boundTranscludeFn
  ){}
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$controllerProvider
   * @description
   * The {@link angular.module.ng.$controller $controller service} is used by Angular to create new
   * controllers.
   *
   * This provider allows controller registration via the
   * {@link angular.module.ng.$controllerProvider#register register} method.
   */
  function $ControllerProvider() {
    var controllers = {};
  
  
    /**
     * @ngdoc function
     * @name angular.module.ng.$controllerProvider#register
     * @methodOf angular.module.ng.$controllerProvider
     * @param {string} name Controller name
     * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
     *    annotations in the array notation).
     */
    this.register = function(name, constructor) {
      controllers[name] = constructor;
    };
  
  
    this.$get = ['$injector', '$window', function($injector, $window) {
  
      /**
       * @ngdoc function
       * @name angular.module.ng.$controller
       * @requires $injector
       *
       * @param {Function|string} constructor If called with a function then it's considered to be the
       *    controller constructor function. Otherwise it's considered to be a string which is used
       *    to retrieve the controller constructor using the following steps:
       *
       *    * check if a controller with given name is registered via `$controllerProvider`
       *    * check if evaluating the string on the current scope returns a constructor
       *    * check `window[constructor]` on the global `window` object
       *
       * @param {Object} locals Injection locals for Controller.
       * @return {Object} Instance of given controller.
       *
       * @description
       * `$controller` service is responsible for instantiating controllers.
       *
       * It's just simple call to {@link angular.module.AUTO.$injector $injector}, but extracted into
       * a service, so that one can override this service with {@link https://gist.github.com/1649788
       * BC version}.
       */
      return function(constructor, locals) {
        if(isString(constructor)) {
          var name = constructor;
          constructor = controllers.hasOwnProperty(name)
              ? controllers[name]
              : getter(locals.$scope, name, true) || getter($window, name, true);
  
          assertArgFn(constructor, name, true);
        }
  
        return $injector.instantiate(constructor, locals);
      };
    }];
  }
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$defer
   * @requires $browser
   *
   * @description
   * Delegates to {@link angular.module.ng.$browser#defer $browser.defer}, but wraps the `fn` function
   * into a try/catch block and delegates any exceptions to
   * {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
   *
   * In tests you can use `$browser.defer.flush()` to flush the queue of deferred functions.
   *
   * @param {function()} fn A function, who's execution should be deferred.
   * @param {number=} [delay=0] of milliseconds to defer the function execution.
   * @returns {*} DeferId that can be used to cancel the task via `$defer.cancel()`.
   */
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$defer#cancel
   * @methodOf angular.module.ng.$defer
   *
   * @description
   * Cancels a defered task identified with `deferId`.
   *
   * @param {*} deferId Token returned by the `$defer` function.
   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
   */
  function $DeferProvider(){
    this.$get = ['$rootScope', '$browser', function($rootScope, $browser) {
      function defer(fn, delay) {
        return $browser.defer(function() {
          $rootScope.$apply(fn);
        }, delay);
      }
  
      defer.cancel = function(deferId) {
        return $browser.defer.cancel(deferId);
      };
  
      return defer;
    }];
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$document
   * @requires $window
   *
   * @description
   * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
   * element.
   */
  function $DocumentProvider(){
    this.$get = ['$window', function(window){
      return jqLite(window.document);
    }];
  }
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$exceptionHandler
   * @requires $log
   *
   * @description
   * Any uncaught exception in angular expressions is delegated to this service.
   * The default implementation simply delegates to `$log.error` which logs it into
   * the browser console.
   *
   * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
   * {@link angular.module.ngMock.$exceptionHandler mock $exceptionHandler}
   *
   * @param {Error} exception Exception associated with the error.
   * @param {string=} cause optional information about the context in which
   *       the error was thrown.
   */
  function $ExceptionHandlerProvider() {
    this.$get = ['$log', function($log){
      return function(exception, cause) {
        $log.error.apply($log, arguments);
      };
    }];
  }
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$interpolateProvider
   * @function
   *
   * @description
   *
   * Used for configuring the interpolation markup. Deafults to `{{` and `}}`.
   */
  function $InterpolateProvider() {
    var startSymbol = '{{';
    var endSymbol = '}}';
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$interpolateProvider#startSymbol
     * @methodOf angular.module.ng.$interpolateProvider
     * @description
     * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
     *
     * @prop {string=} value new value to set the starting symbol to.
     */
    this.startSymbol = function(value){
      if (value) {
        startSymbol = value;
        return this;
      } else {
        return startSymbol;
      }
    };
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$interpolateProvider#endSymbol
     * @methodOf angular.module.ng.$interpolateProvider
     * @description
     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
     *
     * @prop {string=} value new value to set the ending symbol to.
     */
    this.endSymbol = function(value){
      if (value) {
        endSymbol = value;
        return this;
      } else {
        return startSymbol;
      }
    };
  
  
    this.$get = ['$parse', function($parse) {
      var startSymbolLength = startSymbol.length,
          endSymbolLength = endSymbol.length;
  
      /**
       * @ngdoc function
       * @name angular.module.ng.$interpolate
       * @function
       *
       * @requires $parse
       *
       * @description
       *
       * Compiles a string with markup into an interpolation function. This service is used by the
       * HTML {@link angular.module.ng.$compile $compile} service for data binding. See
       * {@link angular.module.ng.$interpolateProvider $interpolateProvider} for configuring the
       * interpolation markup.
       *
       *
         <pre>
           var $interpolate = ...; // injected
           var exp = $interpolate('Hello {{name}}!');
           expect(exp({name:'Angular'}).toEqual('Hello Angular!');
         </pre>
       *
       *
       * @param {string} text The text with markup to interpolate.
       * @param {boolean=} 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.
       * @returns {function(context)} an interpolation function which is used to compute the interpolated
       *    string. The function has these parameters:
       *
       *    * `context`: an object against which any expressions embedded in the strings are evaluated
       *      against.
       *
       */
      return function(text, mustHaveExpression) {
        var startIndex,
            endIndex,
            index = 0,
            parts = [],
            length = text.length,
            hasInterpolation = false,
            fn,
            exp,
            concat = [];
  
        while(index < length) {
          if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
               ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
            (index != startIndex) && parts.push(text.substring(index, startIndex));
            parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
            fn.exp = exp;
            index = endIndex + endSymbolLength;
            hasInterpolation = true;
          } else {
            // we did not find anything, so we have to add the remainder to the parts array
            (index != length) && parts.push(text.substring(index));
            index = length;
          }
        }
  
        if (!(length = parts.length)) {
          // we added, nothing, must have been an empty string.
          parts.push('');
          length = 1;
        }
  
        if (!mustHaveExpression  || hasInterpolation) {
          concat.length = length;
          fn = function(context) {
            for(var i = 0, ii = length, part; i<ii; i++) {
              if (typeof (part = parts[i]) == 'function') {
                part = part(context);
                if (part == null || part == undefined) {
                  part = '';
                } else if (typeof part != 'string') {
                  part = toJson(part);
                }
              }
              concat[i] = part;
            }
            return concat.join('');
          };
          fn.exp = text;
          fn.parts = parts;
          return fn;
        }
      };
    }];
  }
  
  var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
      PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,
      HASH_MATCH = PATH_MATCH,
      DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
  
  
  /**
   * Encode path using encodeUriSegment, ignoring forward slashes
   *
   * @param {string} path Path to encode
   * @returns {string}
   */
  function encodePath(path) {
    var segments = path.split('/'),
        i = segments.length;
  
    while (i--) {
      segments[i] = encodeUriSegment(segments[i]);
    }
  
    return segments.join('/');
  }
  
  
  function matchUrl(url, obj) {
    var match = URL_MATCH.exec(url);
  
    match = {
        protocol: match[1],
        host: match[3],
        port: int(match[5]) || DEFAULT_PORTS[match[1]] || null,
        path: match[6] || '/',
        search: match[8],
        hash: match[10]
      };
  
    if (obj) {
      obj.$$protocol = match.protocol;
      obj.$$host = match.host;
      obj.$$port = match.port;
    }
  
    return match;
  }
  
  
  function composeProtocolHostPort(protocol, host, port) {
    return protocol + '://' + host + (port == DEFAULT_PORTS[protocol] ? '' : ':' + port);
  }
  
  
  function pathPrefixFromBase(basePath) {
    return basePath.substr(0, basePath.lastIndexOf('/'));
  }
  
  
  function convertToHtml5Url(url, basePath, hashPrefix) {
    var match = matchUrl(url);
  
    // already html5 url
    if (decodeURIComponent(match.path) != basePath || isUndefined(match.hash) ||
        match.hash.indexOf(hashPrefix) !== 0) {
      return url;
    // convert hashbang url -> html5 url
    } else {
      return composeProtocolHostPort(match.protocol, match.host, match.port) +
             pathPrefixFromBase(basePath) + match.hash.substr(hashPrefix.length);
    }
  }
  
  
  function convertToHashbangUrl(url, basePath, hashPrefix) {
    var match = matchUrl(url);
  
    // already hashbang url
    if (decodeURIComponent(match.path) == basePath) {
      return url;
    // convert html5 url -> hashbang url
    } else {
      var search = match.search && '?' + match.search || '',
          hash = match.hash && '#' + match.hash || '',
          pathPrefix = pathPrefixFromBase(basePath),
          path = match.path.substr(pathPrefix.length);
  
      if (match.path.indexOf(pathPrefix) !== 0) {
        throw 'Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !';
      }
  
      return composeProtocolHostPort(match.protocol, match.host, match.port) + basePath +
             '#' + hashPrefix + path + search + hash;
    }
  }
  
  
  /**
   * LocationUrl represents an url
   * This object is exposed as $location service when HTML5 mode is enabled and supported
   *
   * @constructor
   * @param {string} url HTML5 url
   * @param {string} pathPrefix
   */
  function LocationUrl(url, pathPrefix) {
    pathPrefix = pathPrefix || '';
  
    /**
     * Parse given html5 (regular) url string into properties
     * @param {string} url HTML5 url
     * @private
     */
    this.$$parse = function(url) {
      var match = matchUrl(url, this);
  
      if (match.path.indexOf(pathPrefix) !== 0) {
        throw 'Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !';
      }
  
      this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
      this.$$search = parseKeyValue(match.search);
      this.$$hash = match.hash && decodeURIComponent(match.hash) || '';
  
      this.$$compose();
    };
  
    /**
     * Compose url and update `absUrl` property
     * @private
     */
    this.$$compose = function() {
      var search = toKeyValue(this.$$search),
          hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
  
      this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
      this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
                      pathPrefix + this.$$url;
    };
  
    this.$$parse(url);
  }
  
  
  /**
   * LocationHashbangUrl represents url
   * This object is exposed as $location service when html5 history api is disabled or not supported
   *
   * @constructor
   * @param {string} url Legacy url
   * @param {string} hashPrefix Prefix for hash part (containing path and search)
   */
  function LocationHashbangUrl(url, hashPrefix) {
    var basePath;
  
    /**
     * Parse given hashbang url into properties
     * @param {string} url Hashbang url
     * @private
     */
    this.$$parse = function(url) {
      var match = matchUrl(url, this);
  
      if (match.hash && match.hash.indexOf(hashPrefix) !== 0) {
        throw 'Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '" !';
      }
  
      basePath = match.path + (match.search ? '?' + match.search : '');
      match = HASH_MATCH.exec((match.hash || '').substr(hashPrefix.length));
      if (match[1]) {
        this.$$path = (match[1].charAt(0) == '/' ? '' : '/') + decodeURIComponent(match[1]);
      } else {
        this.$$path = '';
      }
  
      this.$$search = parseKeyValue(match[3]);
      this.$$hash = match[5] && decodeURIComponent(match[5]) || '';
  
      this.$$compose();
    };
  
    /**
     * Compose hashbang url and update `absUrl` property
     * @private
     */
    this.$$compose = function() {
      var search = toKeyValue(this.$$search),
          hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
  
      this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
      this.$$absUrl = composeProtocolHostPort(this.$$protocol, this.$$host, this.$$port) +
                      basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
    };
  
    this.$$parse(url);
  }
  
  
  LocationUrl.prototype = {
  
    /**
     * Has any change been replacing ?
     * @private
     */
    $$replace: false,
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#absUrl
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter only.
     *
     * Return full url representation with all segments encoded according to rules specified in
     * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
     *
     * @return {string}
     */
    absUrl: locationGetter('$$absUrl'),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#url
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter / setter.
     *
     * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
     *
     * Change path, search and hash, when called with parameter and return `$location`.
     *
     * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
     * @return {string}
     */
    url: function(url, replace) {
      if (isUndefined(url))
        return this.$$url;
  
      var match = PATH_MATCH.exec(url);
      if (match[1]) this.path(decodeURIComponent(match[1]));
      if (match[2] || match[1]) this.search(match[3] || '');
      this.hash(match[5] || '', replace);
  
      return this;
    },
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#protocol
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter only.
     *
     * Return protocol of current url.
     *
     * @return {string}
     */
    protocol: locationGetter('$$protocol'),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#host
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter only.
     *
     * Return host of current url.
     *
     * @return {string}
     */
    host: locationGetter('$$host'),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#port
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter only.
     *
     * Return port of current url.
     *
     * @return {Number}
     */
    port: locationGetter('$$port'),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#path
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter / setter.
     *
     * Return path of current url when called without any parameter.
     *
     * Change path when called with parameter and return `$location`.
     *
     * Note: Path should always begin with forward slash (/), this method will add the forward slash
     * if it is missing.
     *
     * @param {string=} path New path
     * @return {string}
     */
    path: locationGetterSetter('$$path', function(path) {
      return path.charAt(0) == '/' ? path : '/' + path;
    }),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#search
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter / setter.
     *
     * Return search part (as object) of current url when called without any parameter.
     *
     * Change search part when called with parameter and return `$location`.
     *
     * @param {string|object<string,string>=} search New search params - string or hash object
     * @param {string=} paramValue If `search` is a string, then `paramValue` will override only a
     *    single search parameter. If the value is `null`, the parameter will be deleted.
     *
     * @return {string}
     */
    search: function(search, paramValue) {
      if (isUndefined(search))
        return this.$$search;
  
      if (isDefined(paramValue)) {
        if (paramValue === null) {
          delete this.$$search[search];
        } else {
          this.$$search[search] = paramValue;
        }
      } else {
        this.$$search = isString(search) ? parseKeyValue(search) : search;
      }
  
      this.$$compose();
      return this;
    },
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#hash
     * @methodOf angular.module.ng.$location
     *
     * @description
     * This method is getter / setter.
     *
     * Return hash fragment when called without any parameter.
     *
     * Change hash fragment when called with parameter and return `$location`.
     *
     * @param {string=} hash New hash fragment
     * @return {string}
     */
    hash: locationGetterSetter('$$hash', identity),
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$location#replace
     * @methodOf angular.module.ng.$location
     *
     * @description
     * If called, all changes to $location during current `$digest` will be replacing current history
     * record, instead of adding new one.
     */
    replace: function() {
      this.$$replace = true;
      return this;
    }
  };
  
  LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
  
  function locationGetter(property) {
    return function() {
      return this[property];
    };
  }
  
  
  function locationGetterSetter(property, preprocess) {
    return function(value) {
      if (isUndefined(value))
        return this[property];
  
      this[property] = preprocess(value);
      this.$$compose();
  
      return this;
    };
  }
  
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$location
   *
   * @requires $browser
   * @requires $sniffer
   * @requires $document
   *
   * @description
   * The $location service parses the URL in the browser address bar (based on the {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL available to your application. Changes to the URL in the address bar are reflected into $location service and changes to $location are reflected into the browser address bar.
   *
   * **The $location service:**
   *
   * - Exposes the current URL in the browser address bar, so you can
   *   - Watch and observe the URL.
   *   - Change the URL.
   * - Synchronizes the URL with the browser when the user
   *   - Changes the address bar.
   *   - Clicks the back or forward button (or clicks a History link).
   *   - Clicks on a link.
   * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
   *
   * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular Services: Using $location}
   */
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$locationProvider
   * @description
   * Use the `$locationProvider` to configure how the application deep linking paths are stored.
   */
  function $LocationProvider(){
    var hashPrefix = '',
        html5Mode = false;
  
    /**
     * @ngdoc property
     * @name angular.module.ng.$locationProvider#hashPrefix
     * @methodOf angular.module.ng.$locationProvider
     * @description
     * @param {string=} prefix Prefix for hash part (containing path and search)
     * @returns {*} current value if used as getter or itself (chaining) if used as setter
     */
    this.hashPrefix = function(prefix) {
      if (isDefined(prefix)) {
        hashPrefix = prefix;
        return this;
      } else {
        return hashPrefix;
      }
    }
  
    /**
     * @ngdoc property
     * @name angular.module.ng.$locationProvider#html5Mode
     * @methodOf angular.module.ng.$locationProvider
     * @description
     * @param {string=} mode Use HTML5 strategy if available.
     * @returns {*} current value if used as getter or itself (chaining) if used as setter
     */
    this.html5Mode = function(mode) {
      if (isDefined(mode)) {
        html5Mode = mode;
        return this;
      } else {
        return html5Mode;
      }
    };
  
    this.$get = ['$rootScope', '$browser', '$sniffer', '$document',
        function( $rootScope,   $browser,   $sniffer,   $document) {
      var currentUrl,
          basePath = $browser.baseHref() || '/',
          pathPrefix = pathPrefixFromBase(basePath),
          initUrl = $browser.url();
  
      if (html5Mode) {
        if ($sniffer.history) {
          currentUrl = new LocationUrl(convertToHtml5Url(initUrl, basePath, hashPrefix), pathPrefix);
        } else {
          currentUrl = new LocationHashbangUrl(convertToHashbangUrl(initUrl, basePath, hashPrefix),
                                               hashPrefix);
        }
  
        // link rewriting
        var u = currentUrl,
            absUrlPrefix = composeProtocolHostPort(u.protocol(), u.host(), u.port()) + pathPrefix;
  
        $document.bind('click', function(event) {
          // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
          // currently we open nice url link and redirect then
  
          if (event.ctrlKey || event.metaKey || event.which == 2) return;
  
          var elm = jqLite(event.target);
  
          // traverse the DOM up to find first A tag
          while (elm.length && lowercase(elm[0].nodeName) !== 'a') {
            elm = elm.parent();
          }
  
          var href = elm.attr('href');
          if (!href || isDefined(elm.attr('ng-ext-link')) || elm.attr('target')) return;
  
          // remove same domain from full url links (IE7 always returns full hrefs)
          href = href.replace(absUrlPrefix, '');
  
          // link to different domain (or base path)
          if (href.substr(0, 4) == 'http') return;
  
          // remove pathPrefix from absolute links
          href = href.indexOf(pathPrefix) === 0 ? href.substr(pathPrefix.length) : href;
  
          currentUrl.url(href);
          $rootScope.$apply();
          event.preventDefault();
          // hack to work around FF6 bug 684208 when scenario runner clicks on links
          window.angular['ff-684208-preventDefault'] = true;
        });
      } else {
        currentUrl = new LocationHashbangUrl(initUrl, hashPrefix);
      }
  
      // rewrite hashbang url <> html5 url
      if (currentUrl.absUrl() != initUrl) {
        $browser.url(currentUrl.absUrl(), true);
      }
  
      // update $location when $browser url changes
      $browser.onUrlChange(function(newUrl) {
        if (currentUrl.absUrl() != newUrl) {
          $rootScope.$evalAsync(function() {
            currentUrl.$$parse(newUrl);
          });
          if (!$rootScope.$$phase) $rootScope.$digest();
        }
      });
  
      // update browser
      var changeCounter = 0;
      $rootScope.$watch(function $locationWatch() {
        if ($browser.url() != currentUrl.absUrl()) {
          changeCounter++;
          $rootScope.$evalAsync(function() {
            $browser.url(currentUrl.absUrl(), currentUrl.$$replace);
            currentUrl.$$replace = false;
          });
        }
  
        return changeCounter;
      });
  
      return currentUrl;
  }];
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$log
   * @requires $window
   *
   * @description
   * Simple service for logging. Default implementation writes the message
   * into the browser's console (if present).
   *
   * The main purpose of this service is to simplify debugging and troubleshooting.
   *
   * @example
      <doc:example>
        <doc:source>
           <script>
             function LogCtrl($log) {
               this.$log = $log;
               this.message = 'Hello World!';
             }
           </script>
           <div ng-controller="LogCtrl">
             <p>Reload this page with open console, enter text and hit the log button...</p>
             Message:
             <input type="text" ng-model="message"/>
             <button ng-click="$log.log(message)">log</button>
             <button ng-click="$log.warn(message)">warn</button>
             <button ng-click="$log.info(message)">info</button>
             <button ng-click="$log.error(message)">error</button>
           </div>
        </doc:source>
        <doc:scenario>
        </doc:scenario>
      </doc:example>
   */
  
  function $LogProvider(){
    this.$get = ['$window', function($window){
      return {
        /**
         * @ngdoc method
         * @name angular.module.ng.$log#log
         * @methodOf angular.module.ng.$log
         *
         * @description
         * Write a log message
         */
        log: consoleLog('log'),
  
        /**
         * @ngdoc method
         * @name angular.module.ng.$log#warn
         * @methodOf angular.module.ng.$log
         *
         * @description
         * Write a warning message
         */
        warn: consoleLog('warn'),
  
        /**
         * @ngdoc method
         * @name angular.module.ng.$log#info
         * @methodOf angular.module.ng.$log
         *
         * @description
         * Write an information message
         */
        info: consoleLog('info'),
  
        /**
         * @ngdoc method
         * @name angular.module.ng.$log#error
         * @methodOf angular.module.ng.$log
         *
         * @description
         * Write an error message
         */
        error: consoleLog('error')
      };
  
      function formatError(arg) {
        if (arg instanceof Error) {
          if (arg.stack) {
            arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
                ? 'Error: ' + arg.message + '\n' + arg.stack
                : arg.stack;
          } else if (arg.sourceURL) {
            arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
          }
        }
        return arg;
      }
  
      function consoleLog(type) {
        var console = $window.console || {},
            logFn = console[type] || console.log || noop;
  
        if (logFn.apply) {
          return function() {
            var args = [];
            forEach(arguments, function(arg) {
              args.push(formatError(arg));
            });
            return logFn.apply(console, args);
          };
        }
  
        // we are IE which either doesn't have window.console => this is noop and we do nothing,
        // or we are IE where console.log doesn't have apply so we log at least first 2 args
        return function(arg1, arg2) {
          logFn(arg1, arg2);
        }
      }
    }];
  }
  
  var OPERATORS = {
      'null':function(){return null;},
      'true':function(){return true;},
      'false':function(){return false;},
      undefined:noop,
      '+':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
      '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
      '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
      '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
      '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
      '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
      '=':noop,
      '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
      '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
      '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
      '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
      '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
      '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
      '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
      '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
      '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
  //    '|':function(self, locals, a,b){return a|b;},
      '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
      '!':function(self, locals, a){return !a(self, locals);}
  };
  var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
  
  function lex(text){
    var tokens = [],
        token,
        index = 0,
        json = [],
        ch,
        lastCh = ':'; // can start regexp
  
    while (index < text.length) {
      ch = text.charAt(index);
      if (is('"\'')) {
        readString(ch);
      } else if (isNumber(ch) || is('.') && isNumber(peek())) {
        readNumber();
      } else if (isIdent(ch)) {
        readIdent();
        // identifiers can only be if the preceding char was a { or ,
        if (was('{,') && json[0]=='{' &&
           (token=tokens[tokens.length-1])) {
          token.json = token.text.indexOf('.') == -1;
        }
      } else if (is('(){}[].,;:')) {
        tokens.push({
          index:index,
          text:ch,
          json:(was(':[,') && is('{[')) || is('}]:,')
        });
        if (is('{[')) json.unshift(ch);
        if (is('}]')) json.shift();
        index++;
      } else if (isWhitespace(ch)) {
        index++;
        continue;
      } else {
        var ch2 = ch + peek(),
            fn = OPERATORS[ch],
            fn2 = OPERATORS[ch2];
        if (fn2) {
          tokens.push({index:index, text:ch2, fn:fn2});
          index += 2;
        } else if (fn) {
          tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
          index += 1;
        } else {
          throwError("Unexpected next character ", index, index+1);
        }
      }
      lastCh = ch;
    }
    return tokens;
  
    function is(chars) {
      return chars.indexOf(ch) != -1;
    }
  
    function was(chars) {
      return chars.indexOf(lastCh) != -1;
    }
  
    function peek() {
      return index + 1 < text.length ? text.charAt(index + 1) : false;
    }
    function isNumber(ch) {
      return '0' <= ch && ch <= '9';
    }
    function isWhitespace(ch) {
      return ch == ' ' || ch == '\r' || ch == '\t' ||
             ch == '\n' || ch == '\v' || ch == '\u00A0'; // IE treats non-breaking space as \u00A0
    }
    function isIdent(ch) {
      return 'a' <= ch && ch <= 'z' ||
             'A' <= ch && ch <= 'Z' ||
             '_' == ch || ch == '$';
    }
    function isExpOperator(ch) {
      return ch == '-' || ch == '+' || isNumber(ch);
    }
  
    function throwError(error, start, end) {
      end = end || index;
      throw Error("Lexer Error: " + error + " at column" +
          (isDefined(start)
              ? "s " + start +  "-" + index + " [" + text.substring(start, end) + "]"
              : " " + end) +
          " in expression [" + text + "].");
    }
  
    function readNumber() {
      var number = "";
      var start = index;
      while (index < text.length) {
        var ch = lowercase(text.charAt(index));
        if (ch == '.' || isNumber(ch)) {
          number += ch;
        } else {
          var peekCh = peek();
          if (ch == 'e' && isExpOperator(peekCh)) {
            number += ch;
          } else if (isExpOperator(ch) &&
              peekCh && isNumber(peekCh) &&
              number.charAt(number.length - 1) == 'e') {
            number += ch;
          } else if (isExpOperator(ch) &&
              (!peekCh || !isNumber(peekCh)) &&
              number.charAt(number.length - 1) == 'e') {
            throwError('Invalid exponent');
          } else {
            break;
          }
        }
        index++;
      }
      number = 1 * number;
      tokens.push({index:start, text:number, json:true,
        fn:function() {return number;}});
    }
    function readIdent() {
      var ident = "",
          start = index,
          lastDot, peekIndex, methodName;
  
      while (index < text.length) {
        var ch = text.charAt(index);
        if (ch == '.' || isIdent(ch) || isNumber(ch)) {
          if (ch == '.') lastDot = index;
          ident += ch;
        } else {
          break;
        }
        index++;
      }
  
      //check if this is not a method invocation and if it is back out to last dot
      if (lastDot) {
        peekIndex = index
        while(peekIndex < text.length) {
          var ch = text.charAt(peekIndex);
          if (ch == '(') {
            methodName = ident.substr(lastDot - start + 1);
            ident = ident.substr(0, lastDot - start);
            index = peekIndex;
            break;
          }
          if(isWhitespace(ch)) {
            peekIndex++;
          } else {
            break;
          }
        }
      }
  
  
      var token = {
        index:start,
        text:ident
      };
  
      if (OPERATORS.hasOwnProperty(ident)) {
        token.fn = token.json = OPERATORS[ident];
      } else {
        var getter = getterFn(ident);
        token.fn = extend(function(self, locals) {
          return (getter(self, locals));
        }, {
          assign: function(self, value) {
            return setter(self, ident, value);
          }
        });
      }
  
      tokens.push(token);
  
      if (methodName) {
        tokens.push({
          index:lastDot,
          text: '.',
          json: false
        });
        tokens.push({
          index: lastDot + 1,
          text: methodName,
          json: false
        });
      }
    }
  
    function readString(quote) {
      var start = index;
      index++;
      var string = "";
      var rawString = quote;
      var escape = false;
      while (index < text.length) {
        var ch = text.charAt(index);
        rawString += ch;
        if (escape) {
          if (ch == 'u') {
            var hex = text.substring(index + 1, index + 5);
            if (!hex.match(/[\da-f]{4}/i))
              throwError( "Invalid unicode escape [\\u" + hex + "]");
            index += 4;
            string += String.fromCharCode(parseInt(hex, 16));
          } else {
            var rep = ESCAPE[ch];
            if (rep) {
              string += rep;
            } else {
              string += ch;
            }
          }
          escape = false;
        } else if (ch == '\\') {
          escape = true;
        } else if (ch == quote) {
          index++;
          tokens.push({
            index:start,
            text:rawString,
            string:string,
            json:true,
            fn:function() { return string; }
          });
          return;
        } else {
          string += ch;
        }
        index++;
      }
      throwError("Unterminated quote", start);
    }
  }
  
  /////////////////////////////////////////
  
  function parser(text, json, $filter){
    var ZERO = valueFn(0),
        value,
        tokens = lex(text),
        assignment = _assignment,
        functionCall = _functionCall,
        fieldAccess = _fieldAccess,
        objectIndex = _objectIndex,
        filterChain = _filterChain
    if(json){
      // The extra level of aliasing is here, just in case the lexer misses something, so that
      // we prevent any accidental execution in JSON.
      assignment = logicalOR;
      functionCall =
        fieldAccess =
        objectIndex =
        filterChain =
          function() { throwError("is not valid json", {text:text, index:0}); };
      value = primary();
    } else {
      value = statements();
    }
    if (tokens.length !== 0) {
      throwError("is an unexpected token", tokens[0]);
    }
    return value;
  
    ///////////////////////////////////
    function throwError(msg, token) {
      throw Error("Syntax Error: Token '" + token.text +
        "' " + msg + " at column " +
        (token.index + 1) + " of the expression [" +
        text + "] starting at [" + text.substring(token.index) + "].");
    }
  
    function peekToken() {
      if (tokens.length === 0)
        throw Error("Unexpected end of expression: " + text);
      return tokens[0];
    }
  
    function peek(e1, e2, e3, e4) {
      if (tokens.length > 0) {
        var token = tokens[0];
        var t = token.text;
        if (t==e1 || t==e2 || t==e3 || t==e4 ||
            (!e1 && !e2 && !e3 && !e4)) {
          return token;
        }
      }
      return false;
    }
  
    function expect(e1, e2, e3, e4){
      var token = peek(e1, e2, e3, e4);
      if (token) {
        if (json && !token.json) {
          throwError("is not valid json", token);
        }
        tokens.shift();
        return token;
      }
      return false;
    }
  
    function consume(e1){
      if (!expect(e1)) {
        throwError("is unexpected, expecting [" + e1 + "]", peek());
      }
    }
  
    function unaryFn(fn, right) {
      return function(self, locals) {
        return fn(self, locals, right);
      };
    }
  
    function binaryFn(left, fn, right) {
      return function(self, locals) {
        return fn(self, locals, left, right);
      };
    }
  
    function hasTokens () {
      return tokens.length > 0;
    }
  
    function statements() {
      var statements = [];
      while(true) {
        if (tokens.length > 0 && !peek('}', ')', ';', ']'))
          statements.push(filterChain());
        if (!expect(';')) {
          // optimize for the common case where there is only one statement.
          // TODO(size): maybe we should not support multiple statements?
          return statements.length == 1
            ? statements[0]
            : function(self, locals){
              var value;
              for ( var i = 0; i < statements.length; i++) {
                var statement = statements[i];
                if (statement)
                  value = statement(self, locals);
              }
              return value;
            };
        }
      }
    }
  
    function _filterChain() {
      var left = expression();
      var token;
      while(true) {
        if ((token = expect('|'))) {
          left = binaryFn(left, token.fn, filter());
        } else {
          return left;
        }
      }
    }
  
    function filter() {
      var token = expect();
      var fn = $filter(token.text);
      var argsFn = [];
      while(true) {
        if ((token = expect(':'))) {
          argsFn.push(expression());
        } else {
          var fnInvoke = function(self, locals, input){
            var args = [input];
            for ( var i = 0; i < argsFn.length; i++) {
              args.push(argsFn[i](self, locals));
            }
            return fn.apply(self, args);
          };
          return function() {
            return fnInvoke;
          };
        }
      }
    }
  
    function expression() {
      return assignment();
    }
  
    function _assignment() {
      var left = logicalOR();
      var right;
      var token;
      if ((token = expect('='))) {
        if (!left.assign) {
          throwError("implies assignment but [" +
            text.substring(0, token.index) + "] can not be assigned to", token);
        }
        right = logicalOR();
        return function(self, locals){
          return left.assign(self, right(self, locals), locals);
        };
      } else {
        return left;
      }
    }
  
    function logicalOR() {
      var left = logicalAND();
      var token;
      while(true) {
        if ((token = expect('||'))) {
          left = binaryFn(left, token.fn, logicalAND());
        } else {
          return left;
        }
      }
    }
  
    function logicalAND() {
      var left = equality();
      var token;
      if ((token = expect('&&'))) {
        left = binaryFn(left, token.fn, logicalAND());
      }
      return left;
    }
  
    function equality() {
      var left = relational();
      var token;
      if ((token = expect('==','!='))) {
        left = binaryFn(left, token.fn, equality());
      }
      return left;
    }
  
    function relational() {
      var left = additive();
      var token;
      if ((token = expect('<', '>', '<=', '>='))) {
        left = binaryFn(left, token.fn, relational());
      }
      return left;
    }
  
    function additive() {
      var left = multiplicative();
      var token;
      while ((token = expect('+','-'))) {
        left = binaryFn(left, token.fn, multiplicative());
      }
      return left;
    }
  
    function multiplicative() {
      var left = unary();
      var token;
      while ((token = expect('*','/','%'))) {
        left = binaryFn(left, token.fn, unary());
      }
      return left;
    }
  
    function unary() {
      var token;
      if (expect('+')) {
        return primary();
      } else if ((token = expect('-'))) {
        return binaryFn(ZERO, token.fn, unary());
      } else if ((token = expect('!'))) {
        return unaryFn(token.fn, unary());
      } else {
        return primary();
      }
    }
  
    function _functionIdent(fnScope) {
      var token = expect();
      var element = token.text.split('.');
      var instance = fnScope;
      var key;
      for ( var i = 0; i < element.length; i++) {
        key = element[i];
        if (instance)
          instance = instance[key];
      }
      if (!isFunction(instance)) {
        throwError("should be a function", token);
      }
      return instance;
    }
  
    function primary() {
      var primary;
      if (expect('(')) {
        primary = filterChain();
        consume(')');
      } else if (expect('[')) {
        primary = arrayDeclaration();
      } else if (expect('{')) {
        primary = object();
      } else {
        var token = expect();
        primary = token.fn;
        if (!primary) {
          throwError("not a primary expression", token);
        }
      }
  
      var next, context;
      while ((next = expect('(', '[', '.'))) {
        if (next.text === '(') {
          primary = functionCall(primary, context);
          context = null;
        } else if (next.text === '[') {
          context = primary;
          primary = objectIndex(primary);
        } else if (next.text === '.') {
          context = primary;
          primary = fieldAccess(primary);
        } else {
          throwError("IMPOSSIBLE");
        }
      }
      return primary;
    }
  
    function _fieldAccess(object) {
      var field = expect().text;
      var getter = getterFn(field);
      return extend(
          function(self, locals) {
            return getter(object(self, locals), locals);
          },
          {
            assign:function(self, value, locals) {
              return setter(object(self, locals), field, value);
            }
          }
      );
    }
  
    function _objectIndex(obj) {
      var indexFn = expression();
      consume(']');
      return extend(
        function(self, locals){
          var o = obj(self, locals),
              i = indexFn(self, locals),
              v, p;
  
          if (!o) return undefined;
          v = o[i];
          if (v && v.then) {
            p = v;
            if (!('$$v' in v)) {
              p.$$v = undefined;
              p.then(function(val) { p.$$v = val; });
            }
            v = v.$$v;
          }
          return v;
        }, {
          assign:function(self, value, locals){
            return obj(self, locals)[indexFn(self, locals)] = value;
          }
        });
    }
  
    function _functionCall(fn, contextGetter) {
      var argsFn = [];
      if (peekToken().text != ')') {
        do {
          argsFn.push(expression());
        } while (expect(','));
      }
      consume(')');
      return function(self, locals){
        var args = [],
            context = contextGetter ? contextGetter(self, locals) : self;
  
        for ( var i = 0; i < argsFn.length; i++) {
          args.push(argsFn[i](self, locals));
        }
        var fnPtr = fn(self, locals) || noop;
        // IE stupidity!
        return fnPtr.apply
            ? fnPtr.apply(context, args)
            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
      };
    }
  
    // This is used with json array declaration
    function arrayDeclaration () {
      var elementFns = [];
      if (peekToken().text != ']') {
        do {
          elementFns.push(expression());
        } while (expect(','));
      }
      consume(']');
      return function(self, locals){
        var array = [];
        for ( var i = 0; i < elementFns.length; i++) {
          array.push(elementFns[i](self, locals));
        }
        return array;
      };
    }
  
    function object () {
      var keyValues = [];
      if (peekToken().text != '}') {
        do {
          var token = expect(),
          key = token.string || token.text;
          consume(":");
          var value = expression();
          keyValues.push({key:key, value:value});
        } while (expect(','));
      }
      consume('}');
      return function(self, locals){
        var object = {};
        for ( var i = 0; i < keyValues.length; i++) {
          var keyValue = keyValues[i];
          var value = keyValue.value(self, locals);
          object[keyValue.key] = value;
        }
        return object;
      };
    }
  }
  
  //////////////////////////////////////////////////
  // Parser helper functions
  //////////////////////////////////////////////////
  
  function setter(obj, path, setValue) {
    var element = path.split('.');
    for (var i = 0; element.length > 1; i++) {
      var key = element.shift();
      var propertyObj = obj[key];
      if (!propertyObj) {
        propertyObj = {};
        obj[key] = propertyObj;
      }
      obj = propertyObj;
    }
    obj[element.shift()] = setValue;
    return setValue;
  }
  
  /**
   * Return the value accesible from the object by path. Any undefined traversals are ignored
   * @param {Object} obj starting object
   * @param {string} path path to traverse
   * @param {boolean=true} bindFnToScope
   * @returns value as accesbile by path
   */
  //TODO(misko): this function needs to be removed
  function getter(obj, path, bindFnToScope) {
    if (!path) return obj;
    var keys = path.split('.');
    var key;
    var lastInstance = obj;
    var len = keys.length;
  
    for (var i = 0; i < len; i++) {
      key = keys[i];
      if (obj) {
        obj = (lastInstance = obj)[key];
      }
    }
    if (!bindFnToScope && isFunction(obj)) {
      return bind(lastInstance, obj);
    }
    return obj;
  }
  
  var getterFnCache = {};
  
  function getterFn(path) {
    if (getterFnCache.hasOwnProperty(path)) {
      return getterFnCache[path];
    }
  
    var fn, code = 'var l, fn, p;\n';
    forEach(path.split('.'), function(key, index) {
      code += 'if(!s) return s;\n' +
              'l=s;\n' +
              's='+ (index
                      // we simply direference 's' on any .dot notation
                      ? 's'
                      // but if we are first then we check locals firs, and if so read it first
                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
              'if (s && s.then) {\n' +
                ' if (!("$$v" in s)) {\n' +
                  ' p=s;\n' +
                  ' p.$$v = undefined;\n' +
                  ' p.then(function(v) {p.$$v=v;});\n' +
                  '}\n' +
                ' s=s.$$v\n' +
              '}\n';
    });
    code += 'return s;';
    fn = Function('s', 'k', code);
    fn.toString = function() { return code; };
  
    return getterFnCache[path] = fn;
  }
  
  ///////////////////////////////////
  
  function $ParseProvider() {
    var cache = {};
    this.$get = ['$filter', function($filter) {
      return function(exp) {
        switch(typeof exp) {
          case 'string':
            return cache.hasOwnProperty(exp)
              ? cache[exp]
              : cache[exp] =  parser(exp, false, $filter);
          case 'function':
            return exp;
          default:
            return noop;
        }
      };
    }];
  }
  
  /**
   * @ngdoc service
   * @name angular.module.ng.$q
   * @requires $rootScope
   *
   * @description
   * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
   *
   * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
   * interface for interacting with an object that represents the result of an action that is
   * performed asynchronously, and may or may not be finished at any given point in time.
   *
   * From the perspective of dealing with error handling, deferred and promise apis are to
   * asynchronous programing what `try`, `catch` and `throw` keywords are to synchronous programing.
   *
   * <pre>
   *   // for the purpose of this example let's assume that variables `$q` and `scope` are
   *   // available in the current lexical scope (they could have been injected or passed in).
   *
   *   function asyncGreet(name) {
   *     var deferred = $q.defer();
   *
   *     setTimeout(function() {
   *       // since this fn executes async in a future turn of the event loop, we need to wrap
   *       // our code into an $apply call so that the model changes are properly observed.
   *       scope.$apply(function() {
   *         if (okToGreet(name)) {
   *           deferred.resolve('Hello, ' + name + '!');
   *         } else {
   *           deferred.reject('Greeting ' + name + ' is not allowed.');
   *         }
   *       });
   *     }, 1000);
   *
   *     return deferred.promise;
   *   }
   *
   *   var promise = asyncGreet('Robin Hood');
   *   promise.then(function(greeting) {
   *     alert('Success: ' + greeting);
   *   }, function(reason) {
   *     alert('Failed: ' + reason);
   *   );
   * </pre>
   *
   * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
   * comes in the way of
   * [guarantees that promise and deferred apis make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
   *
   * Additionally the promise api allows for composition that is very hard to do with the
   * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
   * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
   * section on serial or parallel joining of promises.
   *
   *
   * # The Deferred API
   *
   * A new instance of deferred is constructed by calling `$q.defer()`.
   *
   * The purpose of the deferred object is to expose the associated Promise instance as well as apis
   * that can be used for signaling the successful or unsuccessful completion of the task.
   *
   * **Methods**
   *
   * - `resolve(value)` â€“ resolves the derived promise with the `value`. If the value is a rejection
   *   constructed via `$q.reject`, the promise will be rejected instead.
   * - `reject(reason)` â€“ rejects the derived promise with the `reason`. This is equivalent to
   *   resolving it with a rejection constructed via `$q.reject`.
   *
   * **Properties**
   *
   * - promise â€“ `{Promise}` â€“ promise object associated with this deferred.
   *
   *
   * # The Promise API
   *
   * A new promise instance is created when a deferred instance is created and can be retrieved by
   * calling `deferred.promise`.
   *
   * The purpose of the promise object is to allow for interested parties to get access to the result
   * of the deferred task when it completes.
   *
   * **Methods**
   *
   * - `then(successCallback, errorCallback)` â€“ regardless of when the promise was or will be resolved
   *   or rejected calls one of the success or error callbacks asynchronously as soon as the result
   *   is available. The callbacks are called with a single argument the result or rejection reason.
   *
   *   This method *returns a new promise* which is resolved or rejected via the return value of the
   *   `successCallback` or `errorCallback`.
   *
   *
   * # Chaining promises
   *
   * Because calling `then` api of a promise returns a new derived promise, it is easily possible
   * to create a chain of promises:
   *
   * <pre>
   *   promiseB = promiseA.then(function(result) {
   *     return result + 1;
   *   });
   *
   *   // promiseB will be resolved immediately after promiseA is resolved and it's value will be
   *   // the result of promiseA incremented by 1
   * </pre>
   *
   * It is possible to create chains of any length and since a promise can be resolved with another
   * promise (which will defer its resolution further), it is possible to pause/defer resolution of
   * the promises at any point in the chain. This makes it possible to implement powerful apis like
   * $http's response interceptors.
   *
   *
   * # Differences between Kris Kowal's Q and $q
   *
   *  There are three main differences:
   *
   * - $q is integrated with the {@link angular.module.ng.$rootScope.Scope} Scope model observation
   *   mechanism in angular, which means faster propagation of resolution or rejection into your
   *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
   * - $q promises are recognized by the templating engine in angular, which means that in templates
   *   you can treat promises attached to a scope as if they were the resulting values.
   * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains
   *   all the important functionality needed for common async tasks.
   */
  function $QProvider() {
  
    this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
      return qFactory(function(callback) {
        $rootScope.$evalAsync(callback);
      }, $exceptionHandler);
    }];
  }
  
  
  /**
   * Constructs a promise manager.
   *
   * @param {function(function)} nextTick Function for executing functions in the next turn.
   * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
   *     debugging purposes.
   * @returns {object} Promise manager.
   */
  function qFactory(nextTick, exceptionHandler) {
  
    /**
     * @ngdoc
     * @name angular.module.ng.$q#defer
     * @methodOf angular.module.ng.$q
     * @description
     * Creates a `Deferred` object which represents a task which will finish in the future.
     *
     * @returns {Deferred} Returns a new instance of deferred.
     */
    var defer = function() {
      var pending = [],
          value, deferred;
  
      deferred = {
  
        resolve: function(val) {
          if (pending) {
            var callbacks = pending;
            pending = undefined;
            value = ref(val);
  
            if (callbacks.length) {
              nextTick(function() {
                var callback;
                for (var i = 0, ii = callbacks.length; i < ii; i++) {
                  callback = callbacks[i];
                  value.then(callback[0], callback[1]);
                }
              });
            }
          }
        },
  
  
        reject: function(reason) {
          deferred.resolve(reject(reason));
        },
  
  
        promise: {
          then: function(callback, errback) {
            var result = defer();
  
            var wrappedCallback = function(value) {
              try {
                result.resolve((callback || defaultCallback)(value));
              } catch(e) {
                exceptionHandler(e);
                result.reject(e);
              }
            };
  
            var wrappedErrback = function(reason) {
              try {
                result.resolve((errback || defaultErrback)(reason));
              } catch(e) {
                exceptionHandler(e);
                result.reject(e);
              }
            };
  
            if (pending) {
              pending.push([wrappedCallback, wrappedErrback]);
            } else {
              value.then(wrappedCallback, wrappedErrback);
            }
  
            return result.promise;
          }
        }
      };
  
      return deferred;
    };
  
  
    var ref = function(value) {
      if (value && value.then) return value;
      return {
        then: function(callback) {
          var result = defer();
          nextTick(function() {
            result.resolve(callback(value));
          });
          return result.promise;
        }
      };
    };
  
  
    /**
     * @ngdoc
     * @name angular.module.ng.$q#reject
     * @methodOf angular.module.ng.$q
     * @description
     * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
     * used to forward rejection in a chain of promises. If you are dealing with the last promise in
     * a promise chain, you don't need to worry about it.
     *
     * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
     * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
     * a promise error callback and you want to forward the error to the promise derived from the
     * current promise, you have to "rethrow" the error by returning a rejection constructed via
     * `reject`.
     *
     * <pre>
     *   promiseB = promiseA.then(function(result) {
     *     // success: do something and resolve promiseB
     *     //          with the old or a new result
     *     return result;
     *   }, function(reason) {
     *     // error: handle the error if possible and
     *     //        resolve promiseB with newPromiseOrValue,
     *     //        otherwise forward the rejection to promiseB
     *     if (canHandle(reason)) {
     *      // handle the error and recover
     *      return newPromiseOrValue;
     *     }
     *     return $q.reject(reason);
     *   });
     * </pre>
     *
     * @param {*} reason Constant, message, exception or an object representing the rejection reason.
     * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
     */
    var reject = function(reason) {
      return {
        then: function(callback, errback) {
          var result = defer();
          nextTick(function() {
            result.resolve((errback || defaultErrback)(reason));
          });
          return result.promise;
        }
      };
    };
  
  
    /**
     * @ngdoc
     * @name angular.module.ng.$q#when
     * @methodOf angular.module.ng.$q
     * @description
     * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
     * This is useful when you are dealing with on object that might or might not be a promise, or if
     * the promise comes from a source that can't be trusted.
     *
     * @param {*} value Value or a promise
     * @returns {Promise} Returns a single promise that will be resolved with an array of values,
     *   each value coresponding to the promise at the same index in the `promises` array. If any of
     *   the promises is resolved with a rejection, this resulting promise will be resolved with the
     *   same rejection.
     */
    var when = function(value, callback, errback) {
      var result = defer(),
          done;
  
      var wrappedCallback = function(value) {
        try {
          return (callback || defaultCallback)(value);
        } catch (e) {
          exceptionHandler(e);
          return reject(e);
        }
      };
  
      var wrappedErrback = function(reason) {
        try {
          return (errback || defaultErrback)(reason);
        } catch (e) {
          exceptionHandler(e);
          return reject(e);
        }
      };
  
      nextTick(function() {
        ref(value).then(function(value) {
          if (done) return;
          done = true;
          result.resolve(ref(value).then(wrappedCallback, wrappedErrback));
        }, function(reason) {
          if (done) return;
          done = true;
          result.resolve(wrappedErrback(reason));
        });
      });
  
      return result.promise;
    };
  
  
    function defaultCallback(value) {
      return value;
    }
  
  
    function defaultErrback(reason) {
      return reject(reason);
    }
  
  
    /**
     * @ngdoc
     * @name angular.module.ng.$q#all
     * @methodOf angular.module.ng.$q
     * @description
     * Combines multiple promises into a single promise that is resolved when all of the input
     * promises are resolved.
     *
     * @param {Array.<Promise>} promises An array of promises.
     * @returns {Promise} Returns a single promise that will be resolved with an array of values,
     *   each value coresponding to the promise at the same index in the `promises` array. If any of
     *   the promises is resolved with a rejection, this resulting promise will be resolved with the
     *   same rejection.
     */
    function all(promises) {
      var deferred = defer(),
          counter = promises.length,
          results = [];
  
      if (counter) {
        forEach(promises, function(promise, index) {
          ref(promise).then(function(value) {
            if (index in results) return;
            results[index] = value;
            if (!(--counter)) deferred.resolve(results);
          }, function(reason) {
            if (index in results) return;
            deferred.reject(reason);
          });
        });
      } else {
        deferred.resolve(results);
      }
  
      return deferred.promise;
    }
  
    return {
      defer: defer,
      reject: reject,
      when: when,
      all: all
    };
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$routeProvider
   * @function
   *
   * @description
   *
   * Used for configuring routes. See {@link angular.module.ng.$route $route} for an example.
   */
  function $RouteProvider(){
    var routes = {};
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$routeProvider#when
     * @methodOf angular.module.ng.$routeProvider
     *
     * @param {string} path Route path (matched against `$location.path`). If `$location.path`
     *    contains redudant trailing slash or is missing one, the route will still match and the
     *    `$location.path` will be updated to add or drop the trailing slash to exacly match the
     *    route definition.
     * @param {Object} route Mapping information to be assigned to `$route.current` on route
     *    match.
     *
     *    Object properties:
     *
     *    - `controller` â€“ `{function()=}` â€“ Controller fn that should be associated with newly
     *      created scope.
     *    - `template` â€“ `{string=}` â€“ path to an html template that should be used by
     *      {@link angular.module.ng.$compileProvider.directive.ng-view ng-view} or
     *      {@link angular.module.ng.$compileProvider.directive.ng-include ng-include} directives.
     *    - `redirectTo` â€“ {(string|function())=} â€“ value to update
     *      {@link angular.module.ng.$location $location} path with and trigger route redirection.
     *
     *      If `redirectTo` is a function, it will be called with the following parameters:
     *
     *      - `{Object.<string>}` - route parameters extracted from the current
     *        `$location.path()` by applying the current route template.
     *      - `{string}` - current `$location.path()`
     *      - `{Object}` - current `$location.search()`
     *
     *      The custom `redirectTo` function is expected to return a string which will be used
     *      to update `$location.path()` and `$location.search()`.
     *
     *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
     *    changes.
     *
     *      If the option is set to `false` and url in the browser changes, then
     *      `$routeUpdate` event is broadcasted on the root scope.
     *
     * @returns {Object} self
     *
     * @description
     * Adds a new route definition to the `$route` service.
     */
    this.when = function(path, route) {
      routes[path] = extend({reloadOnSearch: true}, route);
  
      // create redirection for trailing slashes
      if (path) {
        var redirectPath = (path[path.length-1] == '/')
            ? path.substr(0, path.length-1)
            : path +'/';
  
        routes[redirectPath] = {redirectTo: path};
      }
  
      return this;
    };
  
    /**
     * @ngdoc method
     * @name angular.module.ng.$routeProvider#otherwise
     * @methodOf angular.module.ng.$routeProvider
     *
     * @description
     * Sets route definition that will be used on route change when no other route definition
     * is matched.
     *
     * @param {Object} params Mapping information to be assigned to `$route.current`.
     * @returns {Object} self
     */
    this.otherwise = function(params) {
      this.when(null, params);
      return this;
    };
  
  
    this.$get = ['$rootScope', '$location', '$routeParams',
        function( $rootScope,  $location,  $routeParams) {
  
      /**
       * @ngdoc object
       * @name angular.module.ng.$route
       * @requires $location
       * @requires $routeParams
       *
       * @property {Object} current Reference to the current route definition.
       * @property {Array.<Object>} routes Array of all configured routes.
       *
       * @description
       * Is used for deep-linking URLs to controllers and views (HTML partials).
       * It watches `$location.url()` and tries to map the path to an existing route definition.
       *
       * You can define routes through {@link angular.module.ng.$routeProvider $routeProvider}'s API.
       *
       * The `$route` service is typically used in conjunction with {@link angular.module.ng.$compileProvider.directive.ng-view ng-view}
       * directive and the {@link angular.module.ng.$routeParams $routeParams} service.
       *
       * @example
         This example shows how changing the URL hash causes the `$route` to match a route against the
         URL, and the `ng-view` pulls in the partial.
  
         Note that this example is using {@link angular.module.ng.$compileProvider.directive.script inlined templates}
         to get it working on jsfiddle as well.
  
        <doc:example module="route">
          <doc:source>
            <script type="text/ng-template" id="examples/book.html">
              controller: {{name}}<br />
              Book Id: {{params.bookId}}<br />
            </script>
  
            <script type="text/ng-template" id="examples/chapter.html">
              controller: {{name}}<br />
              Book Id: {{params.bookId}}<br />
              Chapter Id: {{params.chapterId}}
            </script>
  
            <script>
              angular.module('route', [], function($routeProvider, $locationProvider) {
                $routeProvider.when('/Book/:bookId', {template: 'examples/book.html', controller: BookCntl});
                $routeProvider.when('/Book/:bookId/ch/:chapterId', {template: 'examples/chapter.html', controller: ChapterCntl});
  
                // configure html5 to get links working on jsfiddle
                $locationProvider.html5Mode(true);
              });
  
              function MainCntl($scope, $route, $routeParams, $location) {
                $scope.$route = $route;
                $scope.$location = $location;
                $scope.$routeParams = $routeParams;
              }
  
              function BookCntl($scope, $routeParams) {
                $scope.name = "BookCntl";
                $scope.params = $routeParams;
              }
  
              function ChapterCntl($scope, $routeParams) {
                $scope.name = "ChapterCntl";
                $scope.params = $routeParams;
              }
            </script>
  
            <div ng-controller="MainCntl">
              Choose:
              <a href="/Book/Moby">Moby</a> |
              <a href="/Book/Moby/ch/1">Moby: Ch1</a> |
              <a href="/Book/Gatsby">Gatsby</a> |
              <a href="/Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
              <a href="/Book/Scarlet">Scarlet Letter</a><br/>
  
              <div ng-view></div>
              <hr />
  
              <pre>$location.path() = {{$location.path()}}</pre>
              <pre>$route.current.template = {{$route.current.template}}</pre>
              <pre>$route.current.params = {{$route.current.params}}</pre>
              <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
              <pre>$routeParams = {{$routeParams}}</pre>
            </div>
          </doc:source>
          <doc:scenario>
            it('should load and compile correct template', function() {
              element('a:contains("Moby: Ch1")').click();
              var content = element('.doc-example-live [ng-view]').text();
              expect(content).toMatch(/controller\: ChapterCntl/);
              expect(content).toMatch(/Book Id\: Moby/);
              expect(content).toMatch(/Chapter Id\: 1/);
  
              element('a:contains("Scarlet")').click();
              content = element('.doc-example-live [ng-view]').text();
              expect(content).toMatch(/controller\: BookCntl/);
              expect(content).toMatch(/Book Id\: Scarlet/);
            });
          </doc:scenario>
        </doc:example>
       */
  
      /**
       * @ngdoc event
       * @name angular.module.ng.$route#$beforeRouteChange
       * @eventOf angular.module.ng.$route
       * @eventType broadcast on root scope
       * @description
       * Broadcasted before a route change.
       *
       * @param {Route} next Future route information.
       * @param {Route} current Current route information.
       */
  
      /**
       * @ngdoc event
       * @name angular.module.ng.$route#$afterRouteChange
       * @eventOf angular.module.ng.$route
       * @eventType broadcast on root scope
       * @description
       * Broadcasted after a route change.
       *
       * @param {Route} current Current route information.
       * @param {Route} previous Previous route information.
       */
  
      /**
       * @ngdoc event
       * @name angular.module.ng.$route#$routeUpdate
       * @eventOf angular.module.ng.$route
       * @eventType broadcast on root scope
       * @description
       *
       * The `reloadOnSearch` property has been set to false, and we are reusing the same
       * instance of the Controller.
       */
  
      var matcher = switchRouteMatcher,
          dirty = 0,
          forceReload = false,
          $route = {
            routes: routes,
  
            /**
             * @ngdoc method
             * @name angular.module.ng.$route#reload
             * @methodOf angular.module.ng.$route
             *
             * @description
             * Causes `$route` service to reload the current route even if
             * {@link angular.module.ng.$location $location} hasn't changed.
             *
             * As a result of that, {@link angular.module.ng.$compileProvider.directive.ng-view ng-view}
             * creates new scope, reinstantiates the controller.
             */
            reload: function() {
              dirty++;
              forceReload = true;
            }
          };
  
      $rootScope.$watch(function() { return dirty + $location.url(); }, updateRoute);
  
      return $route;
  
      /////////////////////////////////////////////////////
  
      function switchRouteMatcher(on, when) {
        // TODO(i): this code is convoluted and inefficient, we should construct the route matching
        //   regex only once and then reuse it
        var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$',
            params = [],
            dst = {};
        forEach(when.split(/\W/), function(param) {
          if (param) {
            var paramRegExp = new RegExp(":" + param + "([\\W])");
            if (regex.match(paramRegExp)) {
              regex = regex.replace(paramRegExp, "([^\\/]*)$1");
              params.push(param);
            }
          }
        });
        var match = on.match(new RegExp(regex));
        if (match) {
          forEach(params, function(name, index) {
            dst[name] = match[index + 1];
          });
        }
        return match ? dst : null;
      }
  
      function updateRoute() {
        var next = parseRoute(),
            last = $route.current;
  
        if (next && last && next.$route === last.$route
            && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
          last.params = next.params;
          copy(last.params, $routeParams);
          $rootScope.$broadcast('$routeUpdate', last);
        } else if (next || last) {
          forceReload = false;
          $rootScope.$broadcast('$beforeRouteChange', next, last);
          $route.current = next;
          if (next) {
            if (next.redirectTo) {
              if (isString(next.redirectTo)) {
                $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
                         .replace();
              } else {
                $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
                         .replace();
              }
            } else {
              copy(next.params, $routeParams);
            }
          }
          $rootScope.$broadcast('$afterRouteChange', next, last);
        }
      }
  
  
      /**
       * @returns the current active route, by matching it against the URL
       */
      function parseRoute() {
        // Match a route
        var params, match;
        forEach(routes, function(route, path) {
          if (!match && (params = matcher($location.path(), path))) {
            match = inherit(route, {
              params: extend({}, $location.search(), params),
              pathParams: params});
            match.$route = route;
          }
        });
        // No route matched; fallback to "otherwise" route
        return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
      }
  
      /**
       * @returns interpolation of the redirect path with the parametrs
       */
      function interpolate(string, params) {
        var result = [];
        forEach((string||'').split(':'), function(segment, i) {
          if (i == 0) {
            result.push(segment);
          } else {
            var segmentMatch = segment.match(/(\w+)(.*)/);
            var key = segmentMatch[1];
            result.push(params[key]);
            result.push(segmentMatch[2] || '');
            delete params[key];
          }
        });
        return result.join('');
      }
    }];
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$routeParams
   * @requires $route
   *
   * @description
   * Current set of route parameters. The route parameters are a combination of the
   * {@link angular.module.ng.$location $location} `search()`, and `path()`. The `path` parameters
   * are extracted when the {@link angular.module.ng.$route $route} path is matched.
   *
   * In case of parameter name collision, `path` params take precedence over `search` params.
   *
   * The service guarantees that the identity of the `$routeParams` object will remain unchanged
   * (but its properties will likely change) even when a route change occurs.
   *
   * @example
   * <pre>
   *  // Given:
   *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
   *  // Route: /Chapter/:chapterId/Section/:sectionId
   *  //
   *  // Then
   *  $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
   * </pre>
   */
  function $RouteParamsProvider() {
    this.$get = valueFn({});
  }
  
  /**
   * DESIGN NOTES
   *
   * The design decisions behind the scope ware heavily favored for speed and memory consumption.
   *
   * The typical use of scope is to watch the expressions, which most of the time return the same
   * value as last time so we optimize the operation.
   *
   * Closures construction is expensive from speed as well as memory:
   *   - no closures, instead ups prototypical inheritance for API
   *   - Internal state needs to be stored on scope directly, which means that private state is
   *     exposed as $$____ properties
   *
   * Loop operations are optimized by using while(count--) { ... }
   *   - this means that in order to keep the same order of execution as addition we have to add
   *     items to the array at the begging (shift) instead of at the end (push)
   *
   * Child scopes are created and removed often
   *   - Using array would be slow since inserts in meddle are expensive so we use linked list
   *
   * There are few watches then a lot of observers. This is why you don't want the observer to be
   * implemented in the same way as watch. Watch requires return of initialization function which
   * are expensive to construct.
   */
  
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$rootScopeProvider
   * @description
   *
   * Provider for the $rootScope service.
   */
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$rootScopeProvider#digestTtl
   * @methodOf angular.module.ng.$rootScopeProvider
   * @description
   *
   * Sets the number of digest iteration the scope should attempt to execute before giving up and
   * assuming that the model is unstable.
   *
   * The current default is 10 iterations.
   *
   * @param {number} limit The number of digest iterations.
   */
  
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$rootScope
   * @description
   *
   * Every application has a single root {@link angular.module.ng.$rootScope.Scope scope}.
   * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
   * event processing life-cycle. See {@link guide/dev_guide.scopes developer guide on scopes}.
   */
  function $RootScopeProvider(){
    var TTL = 10;
  
    this.digestTtl = function(value) {
      if (arguments.length) {
        TTL = value;
      }
      return TTL;
    }
  
    this.$get = ['$injector', '$exceptionHandler', '$parse',
        function( $injector,   $exceptionHandler,   $parse) {
  
      /**
       * @ngdoc function
       * @name angular.module.ng.$rootScope.Scope
       *
       * @description
       * A root scope can be retrieved using the {@link angular.module.ng.$rootScope $rootScope} key from the
       * {@link angular.module.AUTO.$injector $injector}. Child scopes are created using the
       * {@link angular.module.ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
       * compiled HTML template is executed.)
       *
       * Here is a simple scope snippet to show how you can interact with the scope.
       * <pre>
          angular.injector(['ng']).invoke(function($rootScope) {
             var scope = $rootScope.$new();
             scope.salutation = 'Hello';
             scope.name = 'World';
  
             expect(scope.greeting).toEqual(undefined);
  
             scope.$watch('name', function() {
               this.greeting = this.salutation + ' ' + this.name + '!';
             }); // initialize the watch
  
             expect(scope.greeting).toEqual(undefined);
             scope.name = 'Misko';
             // still old value, since watches have not been called yet
             expect(scope.greeting).toEqual(undefined);
  
             scope.$digest(); // fire all  the watches
             expect(scope.greeting).toEqual('Hello Misko!');
          });
       * </pre>
       *
       * # Inheritance
       * A scope can inherit from a parent scope, as in this example:
       * <pre>
           var parent = $rootScope;
           var child = parent.$new();
  
           parent.salutation = "Hello";
           child.name = "World";
           expect(child.salutation).toEqual('Hello');
  
           child.salutation = "Welcome";
           expect(child.salutation).toEqual('Welcome');
           expect(parent.salutation).toEqual('Hello');
       * </pre>
       *
       * # Dependency Injection
       * See {@link guide/dev_guide.di dependency injection}.
       *
       *
       * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
       *     for the current scope. Defaults to {@link angular.module.ng}.
       * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
       *     append/override services provided by `providers`. This is handy when unit-testing and having
       *     the need to override a default service.
       * @returns {Object} Newly created scope.
       *
       */
      function Scope() {
        this.$id = nextUid();
        this.$$phase = this.$parent = this.$$watchers =
                       this.$$nextSibling = this.$$prevSibling =
                       this.$$childHead = this.$$childTail = null;
        this['this'] = this.$root =  this;
        this.$$asyncQueue = [];
        this.$$listeners = {};
      }
  
      /**
       * @ngdoc property
       * @name angular.module.ng.$rootScope.Scope#$id
       * @propertyOf angular.module.ng.$rootScope.Scope
       * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
       *   debugging.
       */
  
  
      Scope.prototype = {
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$new
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Creates a new child {@link angular.module.ng.$rootScope.Scope scope}.
         *
         * The parent scope will propagate the {@link angular.module.ng.$rootScope.Scope#$digest $digest()} and
         * {@link angular.module.ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
         * hierarchy using {@link angular.module.ng.$rootScope.Scope#$destroy $destroy()}.
         *
         * {@link angular.module.ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
         * the scope and its child scopes to be permanently detached from the parent and thus stop
         * participating in model change detection and listener notification by invoking.
         *
         * @params {boolean} isolate if true then the scoped does not prototypically inherit from the
         *         parent scope. The scope is isolated, as it can not se parent scope properties.
         *         When creating widgets it is useful for the widget to not accidently read parent
         *         state.
         *
         * @returns {Object} The newly created child scope.
         *
         */
        $new: function(isolate) {
          var Child,
              child;
  
          if (isFunction(isolate)) {
            // TODO: remove at some point
            throw Error('API-CHANGE: Use $controller to instantiate controllers.');
          }
          if (isolate) {
            child = new Scope();
            child.$root = this.$root;
          } else {
            Child = function() {}; // should be anonymous; This is so that when the minifier munges
              // the name it does not become random set of chars. These will then show up as class
              // name in the debugger.
            Child.prototype = this;
            child = new Child();
            child.$id = nextUid();
          }
          child['this'] = child;
          child.$$listeners = {};
          child.$parent = this;
          child.$$asyncQueue = [];
          child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
          child.$$prevSibling = this.$$childTail;
          if (this.$$childHead) {
            this.$$childTail.$$nextSibling = child;
            this.$$childTail = child;
          } else {
            this.$$childHead = this.$$childTail = child;
          }
          return child;
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$watch
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
         *
         * - The `watchExpression` is called on every call to {@link angular.module.ng.$rootScope.Scope#$digest $digest()} and
         *   should return the value which will be watched. (Since {@link angular.module.ng.$rootScope.Scope#$digest $digest()}
         *   reruns when it detects changes the `watchExpression` can execute multiple times per
         *   {@link angular.module.ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
         * - The `listener` is called only when the value from the current `watchExpression` and the
         *   previous call to `watchExpression' are not equal (with the exception of the initial run
         *   see below). The inequality is determined according to
         *   {@link angular.equals} function. To save the value of the object for later comparison
         *   {@link angular.copy} function is used. It also means that watching complex options will
         *   have adverse memory and performance implications.
         * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
         *   is achieved by rerunning the watchers until no changes are detected. The rerun iteration
         *   limit is 100 to prevent infinity loop deadlock.
         *
         *
         * If you want to be notified whenever {@link angular.module.ng.$rootScope.Scope#$digest $digest} is called,
         * you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
         * can execute multiple times per {@link angular.module.ng.$rootScope.Scope#$digest $digest} cycle when a change is
         * detected, be prepared for multiple calls to your listener.)
         *
         * After a watcher is registered with the scope, the `listener` fn is called asynchronously
         * (via {@link angular.module.ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
         * watcher. In rare cases, this is undesirable because the listener is called when the result
         * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
         * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
         * listener was called due to initialization.
         *
         *
         * # Example
           <pre>
             // let's assume that scope was dependency injected as the $rootScope
             var scope = $rootScope;
             scope.name = 'misko';
             scope.counter = 0;
  
             expect(scope.counter).toEqual(0);
             scope.$watch('name', function(newValue, oldValue) { counter = counter + 1; });
             expect(scope.counter).toEqual(0);
  
             scope.$digest();
             // no variable change
             expect(scope.counter).toEqual(0);
  
             scope.name = 'adam';
             scope.$digest();
             expect(scope.counter).toEqual(1);
           </pre>
         *
         *
         *
         * @param {(function()|string)} watchExpression Expression that is evaluated on each
         *    {@link angular.module.ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
         *    call to the `listener`.
         *
         *    - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
         *    - `function(scope)`: called with current `scope` as a parameter.
         * @param {(function()|string)=} listener Callback called whenever the return value of
         *   the `watchExpression` changes.
         *
         *    - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
         *    - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
         *
         * @param {boolean=} objectEquality Compare object for equality rather then for refference.
         * @returns {function()} Returns a deregistration function for this listener.
         */
        $watch: function(watchExp, listener, objectEquality) {
          var scope = this,
              get = compileToFn(watchExp, 'watch'),
              array = scope.$$watchers,
              watcher = {
                fn: listener,
                last: initWatchVal,
                get: get,
                exp: watchExp,
                eq: !!objectEquality
              };
  
          // in the case user pass string, we need to compile it, do we really need this ?
          if (!isFunction(listener)) {
            var listenFn = compileToFn(listener || noop, 'listener');
            watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
          }
  
          if (!array) {
            array = scope.$$watchers = [];
          }
          // we use unshift since we use a while loop in $digest for speed.
          // the while loop reads in reverse order.
          array.unshift(watcher);
  
          return function() {
            arrayRemove(array, watcher);
          };
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$digest
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Process all of the {@link angular.module.ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
         * Because a {@link angular.module.ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
         * `$digest()` keeps calling the {@link angular.module.ng.$rootScope.Scope#$watch watchers} until no more listeners are
         * firing. This means that it is possible to get into an infinite loop. This function will throw
         * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 100.
         *
         * Usually you don't call `$digest()` directly in
         * {@link angular.module.ng.$compileProvider.directive.ng-controller controllers} or in
         * {@link angular.module.ng.$compileProvider.directive directives}.
         * Instead a call to {@link angular.module.ng.$rootScope.Scope#$apply $apply()} (typically from within a
         * {@link angular.module.ng.$compileProvider.directive directives}) will force a `$digest()`.
         *
         * If you want to be notified whenever `$digest()` is called,
         * you can register a `watchExpression` function  with {@link angular.module.ng.$rootScope.Scope#$watch $watch()}
         * with no `listener`.
         *
         * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
         * life-cycle.
         *
         * # Example
           <pre>
             var scope = ...;
             scope.name = 'misko';
             scope.counter = 0;
  
             expect(scope.counter).toEqual(0);
             scope.$watch('name', function(scope, newValue, oldValue) {
               counter = counter + 1;
             });
             expect(scope.counter).toEqual(0);
  
             scope.$digest();
             // no variable change
             expect(scope.counter).toEqual(0);
  
             scope.name = 'adam';
             scope.$digest();
             expect(scope.counter).toEqual(1);
           </pre>
         *
         */
        $digest: function() {
          var watch, value, last,
              watchers,
              asyncQueue,
              length,
              dirty, ttl = TTL,
              next, current, target = this,
              watchLog = [],
              logIdx, logMsg;
  
          flagPhase(target, '$digest');
  
          do {
            dirty = false;
            current = target;
            do {
              asyncQueue = current.$$asyncQueue;
              while(asyncQueue.length) {
                try {
                  current.$eval(asyncQueue.shift());
                } catch (e) {
                  $exceptionHandler(e);
                }
              }
              if ((watchers = current.$$watchers)) {
                // process our watches
                length = watchers.length;
                while (length--) {
                  try {
                    watch = watchers[length];
                    // Most common watches are on primitives, in which case we can short
                    // circuit it with === operator, only when === fails do we use .equals
                    if ((value = watch.get(current)) !== (last = watch.last) &&
                        !(watch.eq
                            ? equals(value, last)
                            : (typeof value == 'number' && typeof last == 'number'
                               && isNaN(value) && isNaN(last)))) {
                      dirty = true;
                      watch.last = watch.eq ? copy(value) : value;
                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
                      if (ttl < 5) {
                        logIdx = 4 - ttl;
                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
                        logMsg = (isFunction(watch.exp))
                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
                            : watch.exp;
                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
                        watchLog[logIdx].push(logMsg);
                      }
                    }
                  } catch (e) {
                    $exceptionHandler(e);
                  }
                }
              }
  
              // 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 (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
                while(current !== target && !(next = current.$$nextSibling)) {
                  current = current.$parent;
                }
              }
            } while ((current = next));
  
            if(dirty && !(ttl--)) {
              throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
                  'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
            }
          } while (dirty || asyncQueue.length);
  
          this.$root.$$phase = null;
        },
  
  
        /**
         * @ngdoc event
         * @name angular.module.$rootScope.Scope#$destroy
         * @eventOf angular.module.ng.$rootScope.Scope
         * @eventType broadcast on scope being destroyed
         *
         * @description
         * Broadcasted when a scope and its children are being destroyed.
         */
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$destroy
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Remove the current scope (and all of its children) from the parent scope. Removal implies
         * that calls to {@link angular.module.ng.$rootScope.Scope#$digest $digest()} will no longer
         * propagate to the current scope and its children. Removal also implies that the current
         * scope is eligible for garbage collection.
         *
         * The `$destroy()` is usually used by directives such as
         * {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat} for managing the
         * unrolling of the loop.
         *
         * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
         * Application code can register a `$destroy` event handler that will give it chance to
         * perform any necessary cleanup.
         */
        $destroy: function() {
          if (this.$root == this) return; // we can't remove the root node;
          var parent = this.$parent;
  
          this.$broadcast('$destroy');
  
          if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
          if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
          if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
          if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$eval
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Executes the `expression` on the current scope returning the result. Any exceptions in the
         * expression are propagated (uncaught). This is useful when evaluating engular expressions.
         *
         * # Example
           <pre>
             var scope = angular.module.ng.$rootScope.Scope();
             scope.a = 1;
             scope.b = 2;
  
             expect(scope.$eval('a+b')).toEqual(3);
             expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
           </pre>
         *
         * @param {(string|function())=} expression An angular expression to be executed.
         *
         *    - `string`: execute using the rules as defined in  {@link guide/dev_guide.expressions expression}.
         *    - `function(scope, locals)`: execute the function with the current `scope` parameter.
         * @param {Object=} locals Hash object of local variables for the expression.
         *
         * @returns {*} The result of evaluating the expression.
         */
        $eval: function(expr, locals) {
          return $parse(expr)(this, locals);
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$evalAsync
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Executes the expression on the current scope at a later point in time.
         *
         * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
         *
         *   - it will execute in the current script execution context (before any DOM rendering).
         *   - at least one {@link angular.module.ng.$rootScope.Scope#$digest $digest cycle} will be performed after
         *     `expression` execution.
         *
         * Any exceptions from the execution of the expression are forwarded to the
         * {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
         *
         * @param {(string|function())=} expression An angular expression to be executed.
         *
         *    - `string`: execute using the rules as defined in  {@link guide/dev_guide.expressions expression}.
         *    - `function(scope)`: execute the function with the current `scope` parameter.
         *
         */
        $evalAsync: function(expr) {
          this.$$asyncQueue.push(expr);
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$apply
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * `$apply()` is used to execute an expression in angular from outside of the angular framework.
         * (For example from browser DOM events, setTimeout, XHR or third party libraries).
         * Because we are calling into the angular framework we need to perform proper scope life-cycle
         * of {@link angular.module.ng.$exceptionHandler exception handling},
         * {@link angular.module.ng.$rootScope.Scope#$digest executing watches}.
         *
         * ## Life cycle
         *
         * # Pseudo-Code of `$apply()`
            function $apply(expr) {
              try {
                return $eval(expr);
              } catch (e) {
                $exceptionHandler(e);
              } finally {
                $root.$digest();
              }
            }
         *
         *
         * Scope's `$apply()` method transitions through the following stages:
         *
         * 1. The {@link guide/dev_guide.expressions expression} is executed using the
         *    {@link angular.module.ng.$rootScope.Scope#$eval $eval()} method.
         * 2. Any exceptions from the execution of the expression are forwarded to the
         *    {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
         * 3. The {@link angular.module.ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
         *    was executed using the {@link angular.module.ng.$rootScope.Scope#$digest $digest()} method.
         *
         *
         * @param {(string|function())=} exp An angular expression to be executed.
         *
         *    - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
         *    - `function(scope)`: execute the function with current `scope` parameter.
         *
         * @returns {*} The result of evaluating the expression.
         */
        $apply: function(expr) {
          try {
            flagPhase(this, '$apply');
            return this.$eval(expr);
          } catch (e) {
            $exceptionHandler(e);
          } finally {
            this.$root.$$phase = null;
            this.$root.$digest();
          }
        },
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$on
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Listen on events of a given type. See {@link angular.module.ng.$rootScope.Scope#$emit $emit} for discussion of
         * event life cycle.
         *
         * @param {string} name Event name to listen on.
         * @param {function(event)} listener Function to call when the event is emitted.
         * @returns {function()} Returns a deregistration function for this listener.
         *
         * The event listener function format is: `function(event)`. The `event` object passed into the
         * listener has the following attributes
         *
         *   - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
         *   - `currentScope` - {Scope}: the current scope which is handling the event.
         *   - `name` - {string}: Name of the event.
         *   - `cancel` - {function=}: calling `cancel` function will cancel further event propagation
         *     (available only for events that were `$emit`-ed).
         *   - `cancelled` - {boolean}: Whether the event was cancelled.
         */
        $on: function(name, listener) {
          var namedListeners = this.$$listeners[name];
          if (!namedListeners) {
            this.$$listeners[name] = namedListeners = [];
          }
          namedListeners.push(listener);
  
          return function() {
            arrayRemove(namedListeners, listener);
          };
        },
  
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$emit
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Dispatches an event `name` upwards through the scope hierarchy notifying the
         * registered {@link angular.module.ng.$rootScope.Scope#$on} listeners.
         *
         * The event life cycle starts at the scope on which `$emit` was called. All
         * {@link angular.module.ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
         * Afterwards, the event traverses upwards toward the root scope and calls all registered
         * listeners along the way. The event will stop propagating if one of the listeners cancels it.
         *
         * Any exception emmited from the {@link angular.module.ng.$rootScope.Scope#$on listeners} will be passed
         * onto the {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
         *
         * @param {string} name Event name to emit.
         * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
         * @return {Object} Event object, see {@link angular.module.ng.$rootScope.Scope#$on}
         */
        $emit: function(name, args) {
          var empty = [],
              namedListeners,
              scope = this,
              event = {
                name: name,
                targetScope: scope,
                cancel: function() {event.cancelled = true;},
                cancelled: false
              },
              listenerArgs = concat([event], arguments, 1),
              i, length;
  
          do {
            namedListeners = scope.$$listeners[name] || empty;
            event.currentScope = scope;
            for (i=0, length=namedListeners.length; i<length; i++) {
              try {
                namedListeners[i].apply(null, listenerArgs);
                if (event.cancelled) return event;
              } catch (e) {
                $exceptionHandler(e);
              }
            }
            //traverse upwards
            scope = scope.$parent;
          } while (scope);
  
          return event;
        },
  
  
        /**
         * @ngdoc function
         * @name angular.module.ng.$rootScope.Scope#$broadcast
         * @methodOf angular.module.ng.$rootScope.Scope
         * @function
         *
         * @description
         * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
         * registered {@link angular.module.ng.$rootScope.Scope#$on} listeners.
         *
         * The event life cycle starts at the scope on which `$broadcast` was called. All
         * {@link angular.module.ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
         * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
         * calls all registered listeners along the way. The event cannot be canceled.
         *
         * Any exception emmited from the {@link angular.module.ng.$rootScope.Scope#$on listeners} will be passed
         * onto the {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
         *
         * @param {string} name Event name to emit.
         * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
         * @return {Object} Event object, see {@link angular.module.ng.$rootScope.Scope#$on}
         */
        $broadcast: function(name, args) {
          var target = this,
              current = target,
              next = target,
              event = { name: name,
                        targetScope: target },
              listenerArgs = concat([event], arguments, 1);
  
          //down while you can, then up and next sibling or up and next sibling until back at root
          do {
            current = next;
            event.currentScope = current;
            forEach(current.$$listeners[name], function(listener) {
              try {
                listener.apply(null, listenerArgs);
              } catch(e) {
                $exceptionHandler(e);
              }
            });
  
            // 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 $digest
            if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
              while(current !== target && !(next = current.$$nextSibling)) {
                current = current.$parent;
              }
            }
          } while ((current = next));
  
          return event;
        }
      };
  
  
      function flagPhase(scope, phase) {
        var root = scope.$root;
  
        if (root.$$phase) {
          throw Error(root.$$phase + ' already in progress');
        }
  
        root.$$phase = phase;
      }
  
      return new Scope();
  
      function compileToFn(exp, name) {
        var fn = $parse(exp);
        assertArgFn(fn, name);
        return fn;
      }
  
      /**
       * function used as an initial value for watchers.
       * because it's uniqueue we can easily tell it apart from other values
       */
      function initWatchVal() {}
    }];
  }
  
  /*
   * HTML Parser By Misko Hevery (misko@hevery.com)
   * based on:  HTML Parser By John Resig (ejohn.org)
   * Original code by Erik Arvidsson, Mozilla Public License
   * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
   *
   * // Use like so:
   * htmlParser(htmlString, {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * });
   *
   */
  
  
  
  /**
   * @ngdoc service
   * @name angular.module.ng.$sanitize
   * @function
   *
   * @description
   *   The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are
   *   then serialized back to properly escaped html string. This means that no unsafe input can make
   *   it into the returned string, however, since our parser is more strict than a typical browser
   *   parser, it's possible that some obscure input, which would be recognized as valid HTML by a
   *   browser, won't make it through the sanitizer.
   *
   * @param {string} html Html input.
   * @returns {string} Sanitized html.
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.snippet =
               '<p style="color:blue">an html\n' +
               '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
               'snippet</p>';
           }
         </script>
         <div ng-controller="Ctrl">
            Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
             <table>
               <tr>
                 <td>Filter</td>
                 <td>Source</td>
                 <td>Rendered</td>
               </tr>
               <tr id="html-filter">
                 <td>html filter</td>
                 <td>
                   <pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre>
                 </td>
                 <td>
                   <div ng-bind-html="snippet"></div>
                 </td>
               </tr>
               <tr id="escaped-html">
                 <td>no filter</td>
                 <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
                 <td><div ng-bind="snippet"></div></td>
               </tr>
               <tr id="html-unsafe-filter">
                 <td>unsafe html filter</td>
                 <td><pre>&lt;div ng-bind-html-unsafe="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
                 <td><div ng-bind-html-unsafe="snippet"></div></td>
               </tr>
             </table>
           </div>
       </doc:source>
       <doc:scenario>
         it('should sanitize the html snippet ', function() {
           expect(using('#html-filter').element('div').html()).
             toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
         });
  
         it('should escape snippet without any filter', function() {
           expect(using('#escaped-html').element('div').html()).
             toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
                  "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
                  "snippet&lt;/p&gt;");
         });
  
         it('should inline raw snippet if filtered as unsafe', function() {
           expect(using('#html-unsafe-filter').element("div").html()).
             toBe("<p style=\"color:blue\">an html\n" +
                  "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
                  "snippet</p>");
         });
  
         it('should update', function() {
           input('snippet').enter('new <b>text</b>');
           expect(using('#html-filter').binding('snippet')).toBe('new <b>text</b>');
           expect(using('#escaped-html').element('div').html()).toBe("new &lt;b&gt;text&lt;/b&gt;");
           expect(using('#html-unsafe-filter').binding("snippet")).toBe('new <b>text</b>');
         });
       </doc:scenario>
     </doc:example>
   */
  
  function $SanitizeProvider() {
    this.$get = valueFn(function(html) {
      var buf = [];
      htmlParser(html, htmlSanitizeWriter(buf));
      return buf.join('');
    });
  };
  
  // Regular Expressions for parsing tags and attributes
  var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
    END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
    ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
    BEGIN_TAG_REGEXP = /^</,
    BEGING_END_TAGE_REGEXP = /^<\s*\//,
    COMMENT_REGEXP = /<!--(.*?)-->/g,
    CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
    URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/,
    NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
  
  
  // Good source of info about elements and attributes
  // http://dev.w3.org/html5/spec/Overview.html#semantics
  // http://simon.html5.org/html-elements
  
  // Safe Void Elements - HTML5
  // http://dev.w3.org/html5/spec/Overview.html#void-elements
  var voidElements = makeMap("area,br,col,hr,img,wbr");
  
  // Elements that you can, intentionally, leave open (and which close themselves)
  // http://dev.w3.org/html5/spec/Overview.html#optional-tags
  var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
      optionalEndTagInlineElements = makeMap("rp,rt"),
      optionalEndTagElements = extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
  
  // Safe Block Elements - HTML5
  var blockElements = extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," +
          "blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
          "header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
  
  // Inline Elements - HTML5
  var inlineElements = extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," +
          "big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
          "span,strike,strong,sub,sup,time,tt,u,var"));
  
  
  // Special Elements (can contain anything)
  var specialElements = makeMap("script,style");
  
  var validElements = extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
  
  //Attributes that have href and hence need to be sanitized
  var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
  var validAttrs = extend({}, uriAttrs, makeMap(
      'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
      'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
      'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
      'scope,scrolling,shape,span,start,summary,target,title,type,'+
      'valign,value,vspace,width'));
  
  /**
   * @example
   * htmlParser(htmlString, {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * });
   *
   * @param {string} html string
   * @param {object} handler
   */
  function htmlParser( html, handler ) {
    var index, chars, match, stack = [], last = html;
    stack.last = function() { return stack[ stack.length - 1 ]; };
  
    while ( html ) {
      chars = true;
  
      // Make sure we're not in a script or style element
      if ( !stack.last() || !specialElements[ stack.last() ] ) {
  
        // Comment
        if ( html.indexOf("<!--") === 0 ) {
          index = html.indexOf("-->");
  
          if ( index >= 0 ) {
            if (handler.comment) handler.comment( html.substring( 4, index ) );
            html = html.substring( index + 3 );
            chars = false;
          }
  
        // end tag
        } else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
          match = html.match( END_TAG_REGEXP );
  
          if ( match ) {
            html = html.substring( match[0].length );
            match[0].replace( END_TAG_REGEXP, parseEndTag );
            chars = false;
          }
  
        // start tag
        } else if ( BEGIN_TAG_REGEXP.test(html) ) {
          match = html.match( START_TAG_REGEXP );
  
          if ( match ) {
            html = html.substring( match[0].length );
            match[0].replace( START_TAG_REGEXP, parseStartTag );
            chars = false;
          }
        }
  
        if ( chars ) {
          index = html.indexOf("<");
  
          var text = index < 0 ? html : html.substring( 0, index );
          html = index < 0 ? "" : html.substring( index );
  
          if (handler.chars) handler.chars( decodeEntities(text) );
        }
  
      } else {
        html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), function(all, text){
          text = text.
            replace(COMMENT_REGEXP, "$1").
            replace(CDATA_REGEXP, "$1");
  
          if (handler.chars) handler.chars( decodeEntities(text) );
  
          return "";
        });
  
        parseEndTag( "", stack.last() );
      }
  
      if ( html == last ) {
        throw "Parse Error: " + html;
      }
      last = html;
    }
  
    // Clean up any remaining tags
    parseEndTag();
  
    function parseStartTag( tag, tagName, rest, unary ) {
      tagName = lowercase(tagName);
      if ( blockElements[ tagName ] ) {
        while ( stack.last() && inlineElements[ stack.last() ] ) {
          parseEndTag( "", stack.last() );
        }
      }
  
      if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
        parseEndTag( "", tagName );
      }
  
      unary = voidElements[ tagName ] || !!unary;
  
      if ( !unary )
        stack.push( tagName );
  
      var attrs = {};
  
      rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) {
        var value = doubleQuotedValue
          || singleQoutedValue
          || unqoutedValue
          || '';
  
        attrs[name] = decodeEntities(value);
      });
      if (handler.start) handler.start( tagName, attrs, unary );
    }
  
    function parseEndTag( tag, tagName ) {
      var pos = 0, i;
      tagName = lowercase(tagName);
      if ( tagName )
        // Find the closest opened tag of the same type
        for ( pos = stack.length - 1; pos >= 0; pos-- )
          if ( stack[ pos ] == tagName )
            break;
  
      if ( pos >= 0 ) {
        // Close all the open elements, up the stack
        for ( i = stack.length - 1; i >= pos; i-- )
          if (handler.end) handler.end( stack[ i ] );
  
        // Remove the open elements from the stack
        stack.length = pos;
      }
    }
  }
  
  /**
   * decodes all entities into regular string
   * @param value
   * @returns {string} A string with decoded entities.
   */
  var hiddenPre=document.createElement("pre");
  function decodeEntities(value) {
    hiddenPre.innerHTML=value.replace(/</g,"&lt;");
    return hiddenPre.innerText || hiddenPre.textContent || '';
  }
  
  /**
   * Escapes all potentially dangerous characters, so that the
   * resulting string can be safely inserted into attribute or
   * element text.
   * @param value
   * @returns escaped text
   */
  function encodeEntities(value) {
    return value.
      replace(/&/g, '&amp;').
      replace(NON_ALPHANUMERIC_REGEXP, function(value){
        return '&#' + value.charCodeAt(0) + ';';
      }).
      replace(/</g, '&lt;').
      replace(/>/g, '&gt;');
  }
  
  /**
   * create an HTML/XML writer which writes to buffer
   * @param {Array} buf use buf.jain('') to get out sanitized html string
   * @returns {object} in the form of {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * }
   */
  function htmlSanitizeWriter(buf){
    var ignore = false;
    var out = bind(buf, buf.push);
    return {
      start: function(tag, attrs, unary){
        tag = lowercase(tag);
        if (!ignore && specialElements[tag]) {
          ignore = tag;
        }
        if (!ignore && validElements[tag] == true) {
          out('<');
          out(tag);
          forEach(attrs, function(value, key){
            var lkey=lowercase(key);
            if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
              out(' ');
              out(key);
              out('="');
              out(encodeEntities(value));
              out('"');
            }
          });
          out(unary ? '/>' : '>');
        }
      },
      end: function(tag){
          tag = lowercase(tag);
          if (!ignore && validElements[tag] == true) {
            out('</');
            out(tag);
            out('>');
          }
          if (tag == ignore) {
            ignore = false;
          }
        },
      chars: function(chars){
          if (!ignore) {
            out(encodeEntities(chars));
          }
        }
    };
  }
  
  /**
   * !!! This is an undocumented "private" service !!!
   *
   * @name angular.module.ng.$sniffer
   * @requires $window
   *
   * @property {boolean} history Does the browser support html5 history api ?
   * @property {boolean} hashchange Does the browser support hashchange event ?
   *
   * @description
   * This is very simple implementation of testing browser's features.
   */
  function $SnifferProvider() {
    this.$get = ['$window', function($window) {
      var eventSupport = {};
  
      return {
        history: !!($window.history && $window.history.pushState),
        hashchange: 'onhashchange' in $window &&
                    // IE8 compatible mode lies
                    (!$window.document.documentMode || $window.document.documentMode > 7),
        hasEvent: function(event) {
          if (isUndefined(eventSupport[event])) {
            var divElm = $window.document.createElement('div');
            eventSupport[event] = 'on' + event in divElm;
          }
  
          return eventSupport[event];
        }
      };
    }];
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$window
   *
   * @description
   * A reference to the browser's `window` object. While `window`
   * is globally available in JavaScript, it causes testability problems, because
   * it is a global variable. In angular we always refer to it through the
   * `$window` service, so it may be overriden, removed or mocked for testing.
   *
   * All expressions are evaluated with respect to current scope so they don't
   * suffer from window globality.
   *
   * @example
     <doc:example>
       <doc:source>
         <input ng-init="$window = $service('$window'); greeting='Hello World!'" type="text" ng-model="greeting" />
         <button ng-click="$window.alert(greeting)">ALERT</button>
       </doc:source>
       <doc:scenario>
       </doc:scenario>
     </doc:example>
   */
  function $WindowProvider(){
    this.$get = valueFn(window);
  }
  
  /**
   * Parse headers into key value object
   *
   * @param {string} headers Raw headers as a string
   * @returns {Object} Parsed headers as key value object
   */
  function parseHeaders(headers) {
    var parsed = {}, key, val, i;
  
    if (!headers) return parsed;
  
    forEach(headers.split('\n'), function(line) {
      i = line.indexOf(':');
      key = lowercase(trim(line.substr(0, i)));
      val = trim(line.substr(i + 1));
  
      if (key) {
        if (parsed[key]) {
          parsed[key] += ', ' + val;
        } else {
          parsed[key] = val;
        }
      }
    });
  
    return parsed;
  }
  
  
  /**
   * Returns a function that provides access to parsed headers.
   *
   * Headers are lazy parsed when first requested.
   * @see parseHeaders
   *
   * @param {(string|Object)} headers Headers to provide access to.
   * @returns {function(string=)} Returns a getter function which if called with:
   *
   *   - if called with single an argument returns a single header value or null
   *   - if called with no arguments returns an object containing all headers.
   */
  function headersGetter(headers) {
    var headersObj = isObject(headers) ? headers : undefined;
  
    return function(name) {
      if (!headersObj) headersObj =  parseHeaders(headers);
  
      if (name) {
        return headersObj[lowercase(name)] || null;
      }
  
      return headersObj;
    };
  }
  
  
  /**
   * Chain all given functions
   *
   * This function is used for both request and response transforming
   *
   * @param {*} data Data to transform.
   * @param {function(string=)} headers Http headers getter fn.
   * @param {(function|Array.<function>)} fns Function or an array of functions.
   * @returns {*} Transformed data.
   */
  function transformData(data, headers, fns) {
    if (isFunction(fns))
      return fns(data, headers);
  
    forEach(fns, function(fn) {
      data = fn(data, headers);
    });
  
    return data;
  }
  
  
  function isSuccess(status) {
    return 200 <= status && status < 300;
  }
  
  
  function $HttpProvider() {
    var JSON_START = /^\s*(\[|\{[^\{])/,
        JSON_END = /[\}\]]\s*$/,
        PROTECTION_PREFIX = /^\)\]\}',?\n/;
  
    var $config = this.defaults = {
      // transform incoming response data
      transformResponse: [function(data) {
        if (isString(data)) {
          // strip json vulnerability protection prefix
          data = data.replace(PROTECTION_PREFIX, '');
          if (JSON_START.test(data) && JSON_END.test(data))
            data = fromJson(data, true);
        }
        return data;
      }],
  
      // transform outgoing request data
      transformRequest: [function(d) {
        return isObject(d) && !isFile(d) ? toJson(d) : d;
      }],
  
      // default headers
      headers: {
        common: {
          'Accept': 'application/json, text/plain, */*',
          'X-Requested-With': 'XMLHttpRequest'
        },
        post: {'Content-Type': 'application/json'},
        put:  {'Content-Type': 'application/json'}
      }
    };
  
    var providerResponseInterceptors = this.responseInterceptors = [];
  
    this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
        function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
  
      var defaultCache = $cacheFactory('$http'),
          responseInterceptors = [];
  
      forEach(providerResponseInterceptors, function(interceptor) {
        responseInterceptors.push(
            isString(interceptor)
                ? $injector.get(interceptor)
                : $injector.invoke(interceptor)
        );
      });
  
  
      /**
       * @ngdoc function
       * @name angular.module.ng.$http
       * @requires $httpBacked
       * @requires $browser
       * @requires $cacheFactory
       * @requires $rootScope
       * @requires $q
       * @requires $injector
       *
       * @description
       * The `$http` service is a core Angular service that facilitates communication with the remote
       * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
       * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
       *
       * For unit testing applications that use `$http` service, see
       * {@link angular.module.ngMock.$httpBackend $httpBackend mock}.
       *
       * For a higher level of abstraction, please check out the {@link angular.module.ngResource.$resource
       * $resource} service.
       *
       * The $http API is based on the {@link angular.module.ng.$q deferred/promise APIs} exposed by
       * the $q service. While for simple usage patters this doesn't matter much, for advanced usage,
       * it is important to familiarize yourself with these apis and guarantees they provide.
       *
       *
       * # General usage
       * The `$http` service is a function which takes a single argument â€” a configuration object â€”
       * that is used to generate an http request and returns  a {@link angular.module.ng.$q promise}
       * with two $http specific methods: `success` and `error`.
       *
       * <pre>
       *   $http({method: 'GET', url: '/someUrl'}).
       *     success(function(data, status, headers, config) {
       *       // this callback will be called asynchronously
       *       // when the response is available
       *     }).
       *     error(function(data, status, headers, config) {
       *       // called asynchronously if an error occurs
       *       // or server returns response with status
       *       // code outside of the <200, 400) range
       *     });
       * </pre>
       *
       * Since the returned value of calling the $http function is a Promise object, you can also use
       * the `then` method to register callbacks, and these callbacks will receive a single argument â€“
       * an object representing the response. See the api signature and type info below for more
       * details.
       *
       *
       * # Shortcut methods
       *
       * Since all invocation of the $http service require definition of the http method and url and
       * POST and PUT requests require response body/data to be provided as well, shortcut methods
       * were created to simplify using the api:
       *
       * <pre>
       *   $http.get('/someUrl').success(successCallback);
       *   $http.post('/someUrl', data).success(successCallback);
       * </pre>
       *
       * Complete list of shortcut methods:
       *
       * - {@link angular.module.ng.$http#get $http.get}
       * - {@link angular.module.ng.$http#head $http.head}
       * - {@link angular.module.ng.$http#post $http.post}
       * - {@link angular.module.ng.$http#put $http.put}
       * - {@link angular.module.ng.$http#delete $http.delete}
       * - {@link angular.module.ng.$http#jsonp $http.jsonp}
       *
       *
       * # Setting HTTP Headers
       *
       * The $http service will automatically add certain http headers to all requests. These defaults
       * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
       * object, which currently contains this default configuration:
       *
       * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
       *   - `Accept: application/json, text/plain, * / *`
       *   - `X-Requested-With: XMLHttpRequest`
       * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
       *   - `Content-Type: application/json`
       * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
       *   - `Content-Type: application/json`
       *
       * To add or overwrite these defaults, simply add or remove a property from this configuration
       * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
       * with name equal to the lower-cased http method name, e.g.
       * `$httpProvider.defaults.headers.get['My-Header']='value'`.
       *
       *
       * # Transforming Requests and Responses
       *
       * Both requests and responses can be transformed using transform functions. By default, Angular
       * applies these transformations:
       *
       * Request transformations:
       *
       * - if the `data` property of the request config object contains an object, serialize it into
       *   JSON format.
       *
       * Response transformations:
       *
       *  - if XSRF prefix is detected, strip it (see Security Considerations section below)
       *  - if json response is detected, deserialize it using a JSON parser
       *
       * To override these transformation locally, specify transform functions as `transformRequest`
       * and/or `transformResponse` properties of the config object. To globally override the default
       * transforms, override the `$httpProvider.defaults.transformRequest` and
       * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
       *
       *
       * # Caching
       *
       * To enable caching set the configuration property `cache` to `true`. When the cache is
       * enabled, `$http` stores the response from the server in local cache. Next time the
       * response is served from the cache without sending a request to the server.
       *
       * Note that even if the response is served from cache, delivery of the data is asynchronous in
       * the same way that real requests are.
       *
       * If there are multiple GET requests for the same url that should be cached using the same
       * cache, but the cache is not populated yet, only one request to the server will be made and
       * the remaining requests will be fulfilled using the response for the first request.
       *
       *
       * # Response interceptors
       *
       * Before you start creating interceptors, be sure to understand the
       * {@link angular.module.ng.$q $q and deferred/promise APIs}.
       *
       * For purposes of global error handling, authentication or any kind of synchronous or
       * asynchronous preprocessing of received responses, it is desirable to be able to intercept
       * responses for http requests before they are handed over to the application code that
       * initiated these requests. The response interceptors leverage the {@link angular.module.ng.$q
       * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
       *
       * The interceptors are service factories that are registered with the $httpProvider by
       * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
       * injected with dependencies (if specified) and returns the interceptor  â€” a function that
       * takes a {@link angular.module.ng.$q promise} and returns the original or a new promise.
       *
       * <pre>
       *   // register the interceptor as a service
       *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
       *     return function(promise) {
       *       return promise.then(function(response) {
       *         // do something on success
       *       }, function(response) {
       *         // do something on error
       *         if (canRecover(response)) {
       *           return responseOrNewPromise
       *         }
       *         return $q.reject(response);
       *       });
       *     }
       *   });
       *
       *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
       *
       *
       *   // register the interceptor via an anonymous factory
       *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
       *     return function(promise) {
       *       // same as above
       *     }
       *   });
       * </pre>
       *
       *
       * # Security Considerations
       *
       * When designing web applications, consider security threats from:
       *
       * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
       *   JSON Vulnerability}
       * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
       *
       * Both server and the client must cooperate in order to eliminate these threats. Angular comes
       * pre-configured with strategies that address these issues, but for this to work backend server
       * cooperation is required.
       *
       * ## JSON Vulnerability Protection
       *
       * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
       * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
       * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
       * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
       * Angular will automatically strip the prefix before processing it as JSON.
       *
       * For example if your server needs to return:
       * <pre>
       * ['one','two']
       * </pre>
       *
       * which is vulnerable to attack, your server can return:
       * <pre>
       * )]}',
       * ['one','two']
       * </pre>
       *
       * Angular will strip the prefix, before processing the JSON.
       *
       *
       * ## Cross Site Request Forgery (XSRF) Protection
       *
       * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
       * an unauthorized site can gain your user's private data. Angular provides following mechanism
       * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
       * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
       * runs on your domain could read the cookie, your server can be assured that the XHR came from
       * JavaScript running on your domain.
       *
       * To take advantage of this, your server needs to set a token in a JavaScript readable session
       * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
       * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
       * that only JavaScript running on your domain could have read the token. The token must be
       * unique for each user and must be verifiable by the server (to prevent the JavaScript making
       * up its own tokens). We recommend that the token is a digest of your site's authentication
       * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
       *
       *
       * @param {object} config Object describing the request to be made and how it should be
       *    processed. The object has following properties:
       *
       *    - **method** â€“ `{string}` â€“ HTTP method (e.g. 'GET', 'POST', etc)
       *    - **url** â€“ `{string}` â€“ Absolute or relative URL of the resource that is being requested.
       *    - **params** â€“ `{Object.<string|Object>}` â€“ Map of strings or objects which will be turned to
       *      `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
       *    - **data** â€“ `{string|Object}` â€“ Data to be sent as the request message data.
       *    - **headers** â€“ `{Object}` â€“ Map of strings representing HTTP headers to send to the server.
       *    - **transformRequest** â€“ `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` â€“
       *      transform function or an array of such functions. The transform function takes the http
       *      request body and headers and returns its transformed (typically serialized) version.
       *    - **transformResponse** â€“ `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` â€“
       *      transform function or an array of such functions. The transform function takes the http
       *      response body and headers and returns its transformed (typically deserialized) version.
       *    - **cache** â€“ `{boolean|Cache}` â€“ If true, a default $http cache will be used to cache the
       *      GET request, otherwise if a cache instance built with
       *      {@link angular.module.ng.$cacheFactory $cacheFactory}, this cache will be used for
       *      caching.
       *    - **timeout** â€“ `{number}` â€“ timeout in milliseconds.
       *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
       *      XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
       *      requests with credentials} for more information.
       *
       * @returns {HttpPromise} Returns a {@link angular.module.ng.$q promise} object with the
       *   standard `then` method and two http specific methods: `success` and `error`. The `then`
       *   method takes two arguments a success and an error callback which will be called with a
       *   response object. The `success` and `error` methods take a single argument - a function that
       *   will be called when the request succeeds or fails respectively. The arguments passed into
       *   these functions are destructured representation of the response object passed into the
       *   `then` method. The response object has these properties:
       *
       *   - **data** â€“ `{string|Object}` â€“ The response body transformed with the transform functions.
       *   - **status** â€“ `{number}` â€“ HTTP status code of the response.
       *   - **headers** â€“ `{function([headerName])}` â€“ Header getter function.
       *   - **config** â€“ `{Object}` â€“ The configuration object that was used to generate the request.
       *
       * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
       *   requests. This is primarily meant to be used for debugging purposes.
       *
       *
       * @example
          <doc:example>
            <doc:source jsfiddle="false">
              <script>
                function FetchCtrl($scope, $http) {
                  $scope.method = 'GET';
                  $scope.url = 'examples/http-hello.html';
  
                  $scope.fetch = function() {
                    $scope.code = null;
                    $scope.response = null;
  
                    $http({method: $scope.method, url: $scope.url}).
                      success(function(data, status) {
                        $scope.status = status;
                        $scope.data = data;
                      }).
                      error(function(data, status) {
                        $scope.data = data || "Request failed";
                        $scope.status = status;
                    });
                  };
  
                  $scope.updateModel = function(method, url) {
                    $scope.method = method;
                    $scope.url = url;
                  };
                }
              </script>
              <div ng-controller="FetchCtrl">
                <select ng-model="method">
                  <option>GET</option>
                  <option>JSONP</option>
                </select>
                <input type="text" ng-model="url" size="80"/>
                <button ng-click="fetch()">fetch</button><br>
                <button ng-click="updateModel('GET', 'examples/http-hello.html')">Sample GET</button>
                <button ng-click="updateModel('JSONP', 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
                <button ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
                <pre>http status code: {{status}}</pre>
                <pre>http response data: {{data}}</pre>
              </div>
            </doc:source>
            <doc:scenario>
              it('should make an xhr GET request', function() {
                element(':button:contains("Sample GET")').click();
                element(':button:contains("fetch")').click();
                expect(binding('status')).toBe('200');
                expect(binding('data')).toBe('Hello, $http!\n');
              });
  
              it('should make a JSONP request to angularjs.org', function() {
                element(':button:contains("Sample JSONP")').click();
                element(':button:contains("fetch")').click();
                expect(binding('status')).toBe('200');
                expect(binding('data')).toMatch(/Super Hero!/);
              });
  
              it('should make JSONP request to invalid URL and invoke the error handler',
                  function() {
                element(':button:contains("Invalid JSONP")').click();
                element(':button:contains("fetch")').click();
                expect(binding('status')).toBe('0');
                expect(binding('data')).toBe('Request failed');
              });
            </doc:scenario>
          </doc:example>
       */
      function $http(config) {
        config.method = uppercase(config.method);
  
        var reqTransformFn = config.transformRequest || $config.transformRequest,
            respTransformFn = config.transformResponse || $config.transformResponse,
            defHeaders = $config.headers,
            reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
                defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
            reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
            promise;
  
        // strip content-type if data is undefined
        if (isUndefined(config.data)) {
          delete reqHeaders['Content-Type'];
        }
  
        // send request
        promise = sendReq(config, reqData, reqHeaders);
  
  
        // transform future response
        promise = promise.then(transformResponse, transformResponse);
  
        // apply interceptors
        forEach(responseInterceptors, function(interceptor) {
          promise = interceptor(promise);
        });
  
        promise.success = function(fn) {
          promise.then(function(response) {
            fn(response.data, response.status, response.headers, config);
          });
          return promise;
        };
  
        promise.error = function(fn) {
          promise.then(null, function(response) {
            fn(response.data, response.status, response.headers, config);
          });
          return promise;
        };
  
        return promise;
  
        function transformResponse(response) {
          // make a copy since the response must be cacheable
          var resp = extend({}, response, {
            data: transformData(response.data, response.headers, respTransformFn)
          });
          return (isSuccess(response.status))
            ? resp
            : $q.reject(resp);
        }
      }
  
      $http.pendingRequests = [];
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#get
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `GET` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {Object=} config Optional configuration object
       * @returns {HttpPromise} Future object
       */
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#delete
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `DELETE` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {Object=} config Optional configuration object
       * @returns {HttpPromise} Future object
       */
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#head
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `HEAD` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {Object=} config Optional configuration object
       * @returns {XhrFuture} Future object
       */
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#jsonp
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `JSONP` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request.
       *                     Should contain `JSON_CALLBACK` string.
       * @param {Object=} config Optional configuration object
       * @returns {XhrFuture} Future object
       */
      createShortMethods('get', 'delete', 'head', 'jsonp');
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#post
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `POST` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {*} data Request content
       * @param {Object=} config Optional configuration object
       * @returns {HttpPromise} Future object
       */
  
      /**
       * @ngdoc method
       * @name angular.module.ng.$http#put
       * @methodOf angular.module.ng.$http
       *
       * @description
       * Shortcut method to perform `PUT` request
       *
       * @param {string} url Relative or absolute URL specifying the destination of the request
       * @param {*} data Request content
       * @param {Object=} config Optional configuration object
       * @returns {XhrFuture} Future object
       */
      createShortMethodsWithData('post', 'put');
  
  
      return $http;
  
  
      function createShortMethods(names) {
        forEach(arguments, function(name) {
          $http[name] = function(url, config) {
            return $http(extend(config || {}, {
              method: name,
              url: url
            }));
          };
        });
      }
  
  
      function createShortMethodsWithData(name) {
        forEach(arguments, function(name) {
          $http[name] = function(url, data, config) {
            return $http(extend(config || {}, {
              method: name,
              url: url,
              data: data
            }));
          };
        });
      }
  
  
      /**
       * Makes the request
       *
       * !!! ACCESSES CLOSURE VARS:
       * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
       */
      function sendReq(config, reqData, reqHeaders) {
        var deferred = $q.defer(),
            promise = deferred.promise,
            cache,
            cachedResp,
            url = buildUrl(config.url, config.params);
  
        $http.pendingRequests.push(config);
        promise.then(removePendingReq, removePendingReq);
  
  
        if (config.cache && config.method == 'GET') {
          cache = isObject(config.cache) ? config.cache : defaultCache;
        }
  
        if (cache) {
          cachedResp = cache.get(url);
          if (cachedResp) {
            if (cachedResp.then) {
              // cached request has already been sent, but there is no response yet
              cachedResp.then(removePendingReq, removePendingReq);
              return cachedResp;
            } else {
              // serving from cache
              if (isArray(cachedResp)) {
                resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
              } else {
                resolvePromise(cachedResp, 200, {});
              }
            }
          } else {
            // put the promise for the non-transformed response into cache as a placeholder
            cache.put(url, promise);
          }
        }
  
        // if we won't have the response in cache, send the request to the backend
        if (!cachedResp) {
          $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
              config.withCredentials);
        }
  
        return promise;
  
  
        /**
         * Callback registered to $httpBackend():
         *  - caches the response if desired
         *  - resolves the raw $http promise
         *  - calls $apply
         */
        function done(status, response, headersString) {
          if (cache) {
            if (isSuccess(status)) {
              cache.put(url, [status, response, parseHeaders(headersString)]);
            } else {
              // remove promise from the cache
              cache.remove(url);
            }
          }
  
          resolvePromise(response, status, headersString);
          $rootScope.$apply();
        }
  
  
        /**
         * Resolves the raw $http promise.
         */
        function resolvePromise(response, status, headers) {
          // normalize internal statuses to 0
          status = Math.max(status, 0);
  
          (isSuccess(status) ? deferred.resolve : deferred.reject)({
            data: response,
            status: status,
            headers: headersGetter(headers),
            config: config
          });
        }
  
  
        function removePendingReq() {
          var idx = indexOf($http.pendingRequests, config);
          if (idx !== -1) $http.pendingRequests.splice(idx, 1);
        }
      }
  
  
      function buildUrl(url, params) {
            if (!params) return url;
            var parts = [];
            forEachSorted(params, function(value, key) {
              if (value == null || value == undefined) return;
              if (isObject(value)) {
                value = toJson(value);
              }
              parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
            });
            return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
          }
  
  
    }];
  }
  var XHR = window.XMLHttpRequest || function() {
    try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
    throw new Error("This browser does not support XMLHttpRequest.");
  };
  
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$httpBackend
   * @requires $browser
   * @requires $window
   * @requires $document
   *
   * @description
   * HTTP backend used by the {@link angular.module.ng.$http service} that delegates to
   * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
   *
   * You should never need to use this service directly, instead use the higher-level abstractions:
   * {@link angular.module.ng.$http $http} or {@link angular.module.ngResource.$resource $resource}.
   *
   * During testing this implementation is swapped with {@link angular.module.ngMock.$httpBackend mock
   * $httpBackend} which can be trained with responses.
   */
  function $HttpBackendProvider() {
    this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
      return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
          $document[0].body, $window.location.protocol.replace(':', ''));
    }];
  }
  
  function createHttpBackend($browser, XHR, $browserDefer, callbacks, body, locationProtocol) {
    // TODO(vojta): fix the signature
    return function(method, url, post, callback, headers, timeout, withCredentials) {
      $browser.$$incOutstandingRequestCount();
      url = url || $browser.url();
  
      if (lowercase(method) == 'jsonp') {
        var callbackId = '_' + (callbacks.counter++).toString(36);
        callbacks[callbackId] = function(data) {
          callbacks[callbackId].data = data;
        };
  
        var script = $browser.addJs(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
            function() {
          if (callbacks[callbackId].data) {
            completeRequest(callback, 200, callbacks[callbackId].data);
          } else {
            completeRequest(callback, -2);
          }
          delete callbacks[callbackId];
          body.removeChild(script);
        });
      } else {
        var xhr = new XHR();
        xhr.open(method, url, true);
        forEach(headers, function(value, key) {
          if (value) xhr.setRequestHeader(key, value);
        });
  
        var status;
  
        // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
        // response is in the cache. the promise api will ensure that to the app code the api is
        // always async
        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4) {
            completeRequest(
                callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
          }
        };
  
        if (withCredentials) {
          xhr.withCredentials = true;
        }
  
        xhr.send(post || '');
  
        if (timeout > 0) {
          $browserDefer(function() {
            status = -1;
            xhr.abort();
          }, timeout);
        }
      }
  
  
      function completeRequest(callback, status, response, headersString) {
        // URL_MATCH is defined in src/service/location.js
        var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1];
  
        // fix status code for file protocol (it's always 0)
        status = (protocol == 'file') ? (response ? 200 : 404) : status;
  
        // normalize IE bug (http://bugs.jquery.com/ticket/1450)
        status = status == 1223 ? 204 : status;
  
        callback(status, response, headersString);
        $browser.$$completeOutstandingRequest(noop);
      }
    };
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$locale
   *
   * @description
   * $locale service provides localization rules for various Angular components. As of right now the
   * only public api is:
   *
   * * `id` â€“ `{string}` â€“ locale id formatted as `languageId-countryId` (e.g. `en-us`)
   */
  function $LocaleProvider(){
    this.$get = function() {
      return {
        id: 'en-us',
  
        NUMBER_FORMATS: {
          DECIMAL_SEP: '.',
          GROUP_SEP: ',',
          PATTERNS: [
            { // Decimal Pattern
              minInt: 1,
              minFrac: 0,
              maxFrac: 3,
              posPre: '',
              posSuf: '',
              negPre: '-',
              negSuf: '',
              gSize: 3,
              lgSize: 3
            },{ //Currency Pattern
              minInt: 1,
              minFrac: 2,
              maxFrac: 2,
              posPre: '\u00A4',
              posSuf: '',
              negPre: '(\u00A4',
              negSuf: ')',
              gSize: 3,
              lgSize: 3
            }
          ],
          CURRENCY_SYM: '$'
        },
  
        DATETIME_FORMATS: {
          MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
                  .split(','),
          SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
          DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
          SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
          AMPMS: ['AM','PM'],
          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'
        },
  
        pluralCat: function(num) {
          if (num === 1) {
            return 'one';
          }
          return 'other';
        }
      };
    };
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$filterProvider
   * @description
   *
   * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
   * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
   * responsible for creating a the filter function.
   *
   * <pre>
   *   // Filter registration
   *   function MyModule($provide, $filterProvider) {
   *     // create a service to demonstrate injection (not always needed)
   *     $provide.value('greet', function(name){
   *       return 'Hello ' + name + '!':
   *     });
   *
   *     // register a filter factory which uses the
   *     // greet service to demonstrate DI.
   *     $filterProvider.register('greet', function(greet){
   *       // return the filter function which uses the greet service
   *       // to generate salutation
   *       return function(text) {
   *         // filters need to be forgiving so check input validity
   *         return text && greet(text) || text;
   *       };
   *     };
   *   }
   * </pre>
   *
   * The filter function is registered with the `$injector` under the filter name suffixe with `Filter`.
   * <pre>
   *   it('should be the same instance', inject(
   *     function($filterProvider) {
   *       $filterProvider.register('reverse', function(){
   *         return ...;
   *       });
   *     },
   *     function($filter, reverseFilter) {
   *       expect($filter('reverse')).toBe(reverseFilter);
   *     });
   * </pre>
   *
   *
   * For more information about how angular filters work, and how to create your own filters, see
   * {@link guide/dev_guide.templates.filters Understanding Angular Filters} in the angular Developer
   * Guide.
   */
  /**
   * @ngdoc method
   * @name angular.module.ng.$filterProvider#register
   * @methodOf angular.module.ng.$filterProvider
   * @description
   * Register filter factory function.
   *
   * @param {String} name Name of the filter.
   * @param {function} fn The filter factory function which is injectable.
   */
  
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$filter
   * @function
   * @description
   * Filters are used for formatting data displayed to the user.
   *
   * The general syntax in templates is as follows:
   *
   *         {{ expression | [ filter_name ] }}
   *
   * @param {String} name Name of the filter function to retrieve
   * @return {Function} the filter function
   */
  $FilterProvider.$inject = ['$provide'];
  function $FilterProvider($provide) {
    var suffix = 'Filter';
  
    function register(name, factory) {
      return $provide.factory(name + suffix, factory);
    }
    this.register = register;
  
    this.$get = ['$injector', function($injector) {
      return function(name) {
        return $injector.get(name + suffix);
      }
    }];
  
    ////////////////////////////////////////
  
    register('currency', currencyFilter);
    register('date', dateFilter);
    register('filter', filterFilter);
    register('json', jsonFilter);
    register('limitTo', limitToFilter);
    register('linky', linkyFilter);
    register('lowercase', lowercaseFilter);
    register('number', numberFilter);
    register('orderBy', orderByFilter);
    register('uppercase', uppercaseFilter);
  }
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.filter
   * @function
   *
   * @description
   * Selects a subset of items from `array` and returns it as a new array.
   *
   * Note: This function is used to augment the `Array` type in Angular expressions. See
   * {@link angular.module.ng.$filter} for more information about Angular arrays.
   *
   * @param {Array} array The source array.
   * @param {string|Object|function()} expression The predicate to be used for selecting items from
   *   `array`.
   *
   *   Can be one of:
   *
   *   - `string`: Predicate that results in a substring match using the value of `expression`
   *     string. All strings or objects with string properties in `array` that contain this string
   *     will be returned. The predicate can be negated by prefixing the string with `!`.
   *
   *   - `Object`: A pattern object can be used to filter specific properties on objects contained
   *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array 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`: A predicate function can be used to write arbitrary filters. The function is
   *     called for each element of `array`. The final result is an array of those elements that
   *     the predicate returned true for.
   *
   * @example
     <doc:example>
       <doc:source>
         <div ng-init="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'}]"></div>
  
         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>
         <table id="searchObjResults">
           <tr><th>Name</th><th>Phone</th><tr>
           <tr ng-repeat="friend in friends | filter:search">
             <td>{{friend.name}}</td>
             <td>{{friend.phone}}</td>
           <tr>
         </table>
       </doc:source>
       <doc:scenario>
         it('should search across all fields when filtering with a string', function() {
           input('searchText').enter('m');
           expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
             toEqual(['Mary', 'Mike', 'Adam']);
  
           input('searchText').enter('76');
           expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
             toEqual(['John', 'Julie']);
         });
  
         it('should search in specific fields when filtering with a predicate object', function() {
           input('search.$').enter('i');
           expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
             toEqual(['Mary', 'Mike', 'Julie']);
         });
       </doc:scenario>
     </doc:example>
   */
  function filterFilter() {
    return function(array, expression) {
      if (!(array instanceof Array)) return array;
      var predicates = [];
      predicates.check = function(value) {
        for (var j = 0; j < predicates.length; j++) {
          if(!predicates[j](value)) {
            return false;
          }
        }
        return true;
      };
      var search = function(obj, text){
        if (text.charAt(0) === '!') {
          return !search(obj, text.substr(1));
        }
        switch (typeof obj) {
          case "boolean":
          case "number":
          case "string":
            return ('' + obj).toLowerCase().indexOf(text) > -1;
          case "object":
            for ( var objKey in obj) {
              if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
                return true;
              }
            }
            return false;
          case "array":
            for ( var i = 0; i < obj.length; i++) {
              if (search(obj[i], text)) {
                return true;
              }
            }
            return false;
          default:
            return false;
        }
      };
      switch (typeof expression) {
        case "boolean":
        case "number":
        case "string":
          expression = {$:expression};
        case "object":
          for (var key in expression) {
            if (key == '$') {
              (function() {
                var text = (''+expression[key]).toLowerCase();
                if (!text) return;
                predicates.push(function(value) {
                  return search(value, text);
                });
              })();
            } else {
              (function() {
                var path = key;
                var text = (''+expression[key]).toLowerCase();
                if (!text) return;
                predicates.push(function(value) {
                  return search(getter(value, path), text);
                });
              })();
            }
          }
          break;
        case 'function':
          predicates.push(expression);
          break;
        default:
          return array;
      }
      var filtered = [];
      for ( var j = 0; j < array.length; j++) {
        var value = array[j];
        if (predicates.check(value)) {
          filtered.push(value);
        }
      }
      return filtered;
    }
  }
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.currency
   * @function
   *
   * @description
   * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
   * symbol for current locale is used.
   *
   * @param {number} amount Input to filter.
   * @param {string=} symbol Currency symbol or identifier to be displayed.
   * @returns {string} Formatted number.
   *
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.amount = 1234.56;
           }
         </script>
         <div ng-controller="Ctrl">
           <input type="number" ng-model="amount"> <br>
           default currency symbol ($): {{amount | currency}}<br>
           custom currency identifier (USD$): {{amount | currency:"USD$"}}
         </div>
       </doc:source>
       <doc:scenario>
         it('should init with 1234.56', function() {
           expect(binding('amount | currency')).toBe('$1,234.56');
           expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
         });
         it('should update', function() {
           input('amount').enter('-1234');
           expect(binding('amount | currency')).toBe('($1,234.00)');
           expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
         });
       </doc:scenario>
     </doc:example>
   */
  currencyFilter.$inject = ['$locale'];
  function currencyFilter($locale) {
    var formats = $locale.NUMBER_FORMATS;
    return function(amount, currencySymbol){
      if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
      return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
                  replace(/\u00A4/g, currencySymbol);
    };
  }
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.number
   * @function
   *
   * @description
   * Formats a number as text.
   *
   * If the input is not a number an empty string is returned.
   *
   * @param {number|string} number Number to format.
   * @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
   * @returns {string} Number rounded to decimalPlaces and places a â€œ,â€ after each third digit.
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.val = 1234.56789;
           }
         </script>
         <div ng-controller="Ctrl">
           Enter number: <input ng-model='val'><br>
           Default formatting: {{val | number}}<br>
           No fractions: {{val | number:0}}<br>
           Negative number: {{-val | number:4}}
         </div>
       </doc:source>
       <doc:scenario>
         it('should format numbers', function() {
           expect(binding('val | number')).toBe('1,234.568');
           expect(binding('val | number:0')).toBe('1,235');
           expect(binding('-val | number:4')).toBe('-1,234.5679');
         });
  
         it('should update', function() {
           input('val').enter('3374.333');
           expect(binding('val | number')).toBe('3,374.333');
           expect(binding('val | number:0')).toBe('3,374');
           expect(binding('-val | number:4')).toBe('-3,374.3330');
         });
       </doc:scenario>
     </doc:example>
   */
  
  
  numberFilter.$inject = ['$locale'];
  function numberFilter($locale) {
    var formats = $locale.NUMBER_FORMATS;
    return function(number, fractionSize) {
      return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
        fractionSize);
    };
  }
  
  var DECIMAL_SEP = '.';
  function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
    if (isNaN(number) || !isFinite(number)) return '';
  
    var isNegative = number < 0;
    number = Math.abs(number);
    var numStr = number + '',
        formatedText = '',
        parts = [];
  
    if (numStr.indexOf('e') !== -1) {
      formatedText = numStr;
    } else {
      var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
  
      // determine fractionSize if it is not specified
      if (isUndefined(fractionSize)) {
        fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
      }
  
      var pow = Math.pow(10, fractionSize);
      number = Math.round(number * pow) / pow;
      var fraction = ('' + number).split(DECIMAL_SEP);
      var whole = fraction[0];
      fraction = fraction[1] || '';
  
      var pos = 0,
          lgroup = pattern.lgSize,
          group = pattern.gSize;
  
      if (whole.length >= (lgroup + group)) {
        pos = whole.length - lgroup;
        for (var i = 0; i < pos; i++) {
          if ((pos - i)%group === 0 && i !== 0) {
            formatedText += groupSep;
          }
          formatedText += whole.charAt(i);
        }
      }
  
      for (i = pos; i < whole.length; i++) {
        if ((whole.length - i)%lgroup === 0 && i !== 0) {
          formatedText += groupSep;
        }
        formatedText += whole.charAt(i);
      }
  
      // format fraction part.
      while(fraction.length < fractionSize) {
        fraction += '0';
      }
  
      if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
    }
  
    parts.push(isNegative ? pattern.negPre : pattern.posPre);
    parts.push(formatedText);
    parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
    return parts.join('');
  }
  
  function padNumber(num, digits, trim) {
    var neg = '';
    if (num < 0) {
      neg =  '-';
      num = -num;
    }
    num = '' + num;
    while(num.length < digits) num = '0' + num;
    if (trim)
      num = num.substr(num.length - digits);
    return neg + num;
  }
  
  
  function dateGetter(name, size, offset, trim) {
    return function(date) {
      var value = date['get' + name]();
      if (offset > 0 || value > -offset)
        value += offset;
      if (value === 0 && offset == -12 ) value = 12;
      return padNumber(value, size, trim);
    };
  }
  
  function dateStrGetter(name, shortForm) {
    return function(date, formats) {
      var value = date['get' + name]();
      var get = uppercase(shortForm ? ('SHORT' + name) : name);
  
      return formats[get][value];
    };
  }
  
  function timeZoneGetter(date) {
    var offset = date.getTimezoneOffset();
    return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
  }
  
  function ampmGetter(date, formats) {
    return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
  }
  
  var DATE_FORMATS = {
    yyyy: dateGetter('FullYear', 4),
      yy: dateGetter('FullYear', 2, 0, true),
       y: dateGetter('FullYear', 1),
    MMMM: dateStrGetter('Month'),
     MMM: dateStrGetter('Month', true),
      MM: dateGetter('Month', 2, 1),
       M: dateGetter('Month', 1, 1),
      dd: dateGetter('Date', 2),
       d: dateGetter('Date', 1),
      HH: dateGetter('Hours', 2),
       H: dateGetter('Hours', 1),
      hh: dateGetter('Hours', 2, -12),
       h: dateGetter('Hours', 1, -12),
      mm: dateGetter('Minutes', 2),
       m: dateGetter('Minutes', 1),
      ss: dateGetter('Seconds', 2),
       s: dateGetter('Seconds', 1),
    EEEE: dateStrGetter('Day'),
     EEE: dateStrGetter('Day', true),
       a: ampmGetter,
       Z: timeZoneGetter
  };
  
  var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
      NUMBER_STRING = /^\d+$/;
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.date
   * @function
   *
   * @description
   *   Formats `date` to a string based on the requested `format`.
   *
   *   `format` string can be composed of the following elements:
   *
   *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
   *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
   *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
   *   * `'MMMM'`: Month in year (January-December)
   *   * `'MMM'`: Month in year (Jan-Dec)
   *   * `'MM'`: Month in year, padded (01-12)
   *   * `'M'`: Month in year (1-12)
   *   * `'dd'`: Day in month, padded (01-31)
   *   * `'d'`: Day in month (1-31)
   *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
   *   * `'EEE'`: Day in Week, (Sun-Sat)
   *   * `'HH'`: Hour in day, padded (00-23)
   *   * `'H'`: Hour in day (0-23)
   *   * `'hh'`: Hour in am/pm, padded (01-12)
   *   * `'h'`: Hour in am/pm, (1-12)
   *   * `'mm'`: Minute in hour, padded (00-59)
   *   * `'m'`: Minute in hour (0-59)
   *   * `'ss'`: Second in minute, padded (00-59)
   *   * `'s'`: Second in minute (0-59)
   *   * `'a'`: am/pm marker
   *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200)
   *
   *   `format` string can also be one of the following predefined
   *   {@link guide/dev_guide.i18n localizable formats}:
   *
   *   * `'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)
   *
   *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
   *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
   *   (e.g. `"h o''clock"`).
   *
   * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
   *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
   *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
   * @param {string=} format Formatting rules (see Description). If not specified,
   *    `mediumDate` is used.
   * @returns {string} Formatted string or the input if input is not recognized as date/millis.
   *
   * @example
     <doc:example>
       <doc:source>
         <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
             {{1288323623006 | date:'medium'}}<br>
         <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
            {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
         <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
            {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
       </doc:source>
       <doc:scenario>
         it('should format date', function() {
           expect(binding("1288323623006 | date:'medium'")).
              toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
           expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
              toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
           expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
              toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
         });
       </doc:scenario>
     </doc:example>
   */
  dateFilter.$inject = ['$locale'];
  function dateFilter($locale) {
  
  
    var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
    function jsonStringToDate(string){
      var match;
      if (match = string.match(R_ISO8601_STR)) {
        var date = new Date(0),
            tzHour = 0,
            tzMin  = 0;
        if (match[9]) {
          tzHour = int(match[9] + match[10]);
          tzMin = int(match[9] + match[11]);
        }
        date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
        date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
        return date;
      }
      return string;
    }
  
  
    return function(date, format) {
      var text = '',
          parts = [],
          fn, match;
  
      format = format || 'mediumDate'
      format = $locale.DATETIME_FORMATS[format] || format;
      if (isString(date)) {
        if (NUMBER_STRING.test(date)) {
          date = int(date);
        } else {
          date = jsonStringToDate(date);
        }
      }
  
      if (isNumber(date)) {
        date = new Date(date);
      }
  
      if (!isDate(date)) {
        return date;
      }
  
      while(format) {
        match = DATE_FORMATS_SPLIT.exec(format);
        if (match) {
          parts = concat(parts, match, 1);
          format = parts.pop();
        } else {
          parts.push(format);
          format = null;
        }
      }
  
      forEach(parts, function(value){
        fn = DATE_FORMATS[value];
        text += fn ? fn(date, $locale.DATETIME_FORMATS)
                   : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
      });
  
      return text;
    };
  }
  
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.json
   * @function
   *
   * @description
   *   Allows you to convert a JavaScript object into JSON string.
   *
   *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
   *   the binding is automatically converted to JSON.
   *
   * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
   * @returns {string} JSON string.
   *
   * @css ng-monospace Always applied to the encapsulating element.
   *
   * @example:
     <doc:example>
       <doc:source>
         <pre>{{ {'name':'value'} | json }}</pre>
       </doc:source>
       <doc:scenario>
         it('should jsonify filtered objects', function() {
           expect(binding("{'name':'value'}")).toMatch(/\{\n  "name": ?"value"\n}/);
         });
       </doc:scenario>
     </doc:example>
   *
   */
  function jsonFilter() {
    return function(object) {
      return toJson(object, true);
    };
  }
  
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.lowercase
   * @function
   * @description
   * Converts string to lowercase.
   * @see angular.lowercase
   */
  var lowercaseFilter = valueFn(lowercase);
  
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.uppercase
   * @function
   * @description
   * Converts string to uppercase.
   * @see angular.uppercase
   */
  var uppercaseFilter = valueFn(uppercase);
  
  
  /**
   * @ngdoc filter
   * @name angular.module.ng.$filter.linky
   * @function
   *
   * @description
   *   Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
   *   plain email address links.
   *
   * @param {string} text Input text.
   * @returns {string} Html-linkified text.
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.snippet =
               'Pretty text with some links:\n'+
               'http://angularjs.org/,\n'+
               'mailto:us@somewhere.org,\n'+
               'another@somewhere.org,\n'+
               'and one more: ftp://127.0.0.1/.';
           }
         </script>
         <div ng-controller="Ctrl">
         Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
         <table>
           <tr>
             <td>Filter</td>
             <td>Source</td>
             <td>Rendered</td>
           </tr>
           <tr id="linky-filter">
             <td>linky filter</td>
             <td>
               <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
             </td>
             <td>
               <div ng-bind-html="snippet | linky"></div>
             </td>
           </tr>
           <tr id="escaped-html">
             <td>no filter</td>
             <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
             <td><div ng-bind="snippet"></div></td>
           </tr>
         </table>
       </doc:source>
       <doc:scenario>
         it('should linkify the snippet with urls', function() {
           expect(using('#linky-filter').binding('snippet | linky')).
             toBe('Pretty text with some links:&#10;' +
                  '<a href="http://angularjs.org/">http://angularjs.org/</a>,&#10;' +
                  '<a href="mailto:us@somewhere.org">us@somewhere.org</a>,&#10;' +
                  '<a href="mailto:another@somewhere.org">another@somewhere.org</a>,&#10;' +
                  'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
         });
  
         it ('should not linkify snippet without the linky filter', function() {
           expect(using('#escaped-html').binding('snippet')).
             toBe("Pretty text with some links:\n" +
                  "http://angularjs.org/,\n" +
                  "mailto:us@somewhere.org,\n" +
                  "another@somewhere.org,\n" +
                  "and one more: ftp://127.0.0.1/.");
         });
  
         it('should update', function() {
           input('snippet').enter('new http://link.');
           expect(using('#linky-filter').binding('snippet | linky')).
             toBe('new <a href="http://link">http://link</a>.');
           expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
         });
       </doc:scenario>
     </doc:example>
   */
  function linkyFilter() {
    var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
        MAILTO_REGEXP = /^mailto:/;
  
    return function(text) {
      if (!text) return text;
      var match;
      var raw = text;
      var html = [];
      var writer = htmlSanitizeWriter(html);
      var url;
      var i;
      while ((match = raw.match(LINKY_URL_REGEXP))) {
        // We can not end in these as they are sometimes found at the end of the sentence
        url = match[0];
        // if we did not match ftp/http/mailto then assume mailto
        if (match[2] == match[3]) url = 'mailto:' + url;
        i = match.index;
        writer.chars(raw.substr(0, i));
        writer.start('a', {href:url});
        writer.chars(match[0].replace(MAILTO_REGEXP, ''));
        writer.end('a');
        raw = raw.substring(i + match[0].length);
      }
      writer.chars(raw);
      return html.join('');
    };
  };
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$filter.limitTo
   * @function
   *
   * @description
   * Creates a new array containing only a specified number of elements in an array. The elements
   * are taken from either the beginning or the end of the source array, as specified by the
   * value and sign (positive or negative) of `limit`.
   *
   * Note: This function is used to augment the `Array` type in Angular expressions. See
   * {@link angular.module.ng.$filter} for more information about Angular arrays.
   *
   * @param {Array} array Source array to be limited.
   * @param {string|Number} limit The length of the returned array. If the `limit` number is
   *     positive, `limit` number of items from the beginning of the source array are copied.
   *     If the number is negative, `limit` number  of items from the end of the source array are
   *     copied. The `limit` will be trimmed if it exceeds `array.length`
   * @returns {Array} A new sub-array of length `limit` or less if input array had less than `limit`
   *     elements.
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.numbers = [1,2,3,4,5,6,7,8,9];
             $scope.limit = 3;
           }
         </script>
         <div ng-controller="Ctrl">
           Limit {{numbers}} to: <input type="integer" ng-model="limit">
           <p>Output: {{ numbers | limitTo:limit }}</p>
         </div>
       </doc:source>
       <doc:scenario>
         it('should limit the numer array to first three items', function() {
           expect(element('.doc-example-live input[ng-model=limit]').val()).toBe('3');
           expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3]');
         });
  
         it('should update the output when -3 is entered', function() {
           input('limit').enter(-3);
           expect(binding('numbers | limitTo:limit')).toEqual('[7,8,9]');
         });
  
         it('should not exceed the maximum size of input array', function() {
           input('limit').enter(100);
           expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3,4,5,6,7,8,9]');
         });
       </doc:scenario>
     </doc:example>
   */
  function limitToFilter(){
    return function(array, limit) {
      if (!(array instanceof Array)) return array;
      limit = int(limit);
      var out = [],
        i, n;
  
      // check that array is iterable
      if (!array || !(array instanceof Array))
        return out;
  
      // if abs(limit) exceeds maximum length, trim it
      if (limit > array.length)
        limit = array.length;
      else if (limit < -array.length)
        limit = -array.length;
  
      if (limit > 0) {
        i = 0;
        n = limit;
      } else {
        i = array.length + limit;
        n = array.length;
      }
  
      for (; i<n; i++) {
        out.push(array[i]);
      }
  
      return out;
    }
  }
  
  /**
   * @ngdoc function
   * @name angular.module.ng.$filter.orderBy
   * @function
   *
   * @description
   * Orders a specified `array` by the `expression` predicate.
   *
   * Note: this function is used to augment the `Array` type in Angular expressions. See
   * {@link angular.module.ng.$filter} for more informaton about Angular arrays.
   *
   * @param {Array} array The array to sort.
   * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
   *    used by the comparator to determine the order of elements.
   *
   *    Can be one of:
   *
   *    - `function`: Getter function. The result of this function will be sorted using the
   *      `<`, `=`, `>` operator.
   *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
   *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
   *      ascending or descending sort order (for example, +name or -name).
   *    - `Array`: An array of function or string predicates. The first predicate in the array
   *      is used for sorting, but when two items are equivalent, the next predicate is used.
   *
   * @param {boolean=} reverse Reverse the order the array.
   * @returns {Array} Sorted copy of the source array.
   *
   * @example
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.friends =
                 [{name:'John', phone:'555-1212', age:10},
                  {name:'Mary', phone:'555-9876', age:19},
                  {name:'Mike', phone:'555-4321', age:21},
                  {name:'Adam', phone:'555-5678', age:35},
                  {name:'Julie', phone:'555-8765', age:29}]
             $scope.predicate = '-age';
           }
         </script>
         <div ng-controller="Ctrl">
           <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
           <hr/>
           [ <a href="" ng-click="predicate=''">unsorted</a> ]
           <table class="friend">
             <tr>
               <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
                   (<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
               <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
               <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
             <tr>
             <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
               <td>{{friend.name}}</td>
               <td>{{friend.phone}}</td>
               <td>{{friend.age}}</td>
             <tr>
           </table>
         </div>
       </doc:source>
       <doc:scenario>
         it('should be reverse ordered by aged', function() {
           expect(binding('predicate')).toBe('-age');
           expect(repeater('table.friend', 'friend in friends').column('friend.age')).
             toEqual(['35', '29', '21', '19', '10']);
           expect(repeater('table.friend', 'friend in friends').column('friend.name')).
             toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
         });
  
         it('should reorder the table when user selects different predicate', function() {
           element('.doc-example-live a:contains("Name")').click();
           expect(repeater('table.friend', 'friend in friends').column('friend.name')).
             toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
           expect(repeater('table.friend', 'friend in friends').column('friend.age')).
             toEqual(['35', '10', '29', '19', '21']);
  
           element('.doc-example-live a:contains("Phone")').click();
           expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
             toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
           expect(repeater('table.friend', 'friend in friends').column('friend.name')).
             toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
         });
       </doc:scenario>
     </doc:example>
   */
  orderByFilter.$inject = ['$parse'];
  function orderByFilter($parse){
    return function(array, sortPredicate, reverseOrder) {
      if (!(array instanceof Array)) return array;
      if (!sortPredicate) return array;
      sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
      sortPredicate = map(sortPredicate, function(predicate){
        var descending = false, get = predicate || identity;
        if (isString(predicate)) {
          if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
            descending = predicate.charAt(0) == '-';
            predicate = predicate.substring(1);
          }
          get = $parse(predicate);
        }
        return reverseComparator(function(a,b){
          return compare(get(a),get(b));
        }, descending);
      });
      var arrayCopy = [];
      for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
      return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
  
      function comparator(o1, o2){
        for ( var i = 0; i < sortPredicate.length; i++) {
          var comp = sortPredicate[i](o1, o2);
          if (comp !== 0) return comp;
        }
        return 0;
      }
      function reverseComparator(comp, descending) {
        return toBoolean(descending)
            ? function(a,b){return comp(b,a);}
            : comp;
      }
      function compare(v1, v2){
        var t1 = typeof v1;
        var t2 = typeof v2;
        if (t1 == t2) {
          if (t1 == "string") v1 = v1.toLowerCase();
          if (t1 == "string") v2 = v2.toLowerCase();
          if (v1 === v2) return 0;
          return v1 < v2 ? -1 : 1;
        } else {
          return t1 < t2 ? -1 : 1;
        }
      }
    }
  }
  
  function ngDirective(directive) {
    if (isFunction(directive)) {
      directive = {
        link: directive
      }
    }
    directive.restrict = directive.restrict || 'AC';
    return valueFn(directive);
  };
  
  /*
   * Modifies the default behavior of html A tag, so that the default action is prevented when href
   * attribute is empty.
   *
   * The reasoning for this change is to allow easy creation of action links with ng-click without
   * changing the location or causing page reloads, e.g.:
   * <a href="" ng-click="model.$save()">Save</a>
   */
  var htmlAnchorDirective = valueFn({
    restrict: 'E',
    compile: function(element, attr) {
      // turn <a href ng-click="..">link</a> into a link in IE
      // but only if it doesn't have name attribute, in which case it's an anchor
      if (!attr.href) {
        attr.$set('href', '');
      }
  
      return function(scope, element) {
        element.bind('click', function(event){
          // if we have no href url, then don't navigate anywhere.
          if (!element.attr('href')) {
            event.preventDefault();
          }
        });
      }
    }
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-href
   * @restrict A
   *
   * @description
   * Using <angular/> markup like {{hash}} in an href attribute makes
   * the page open to a wrong URL, if the user clicks that link before
   * angular has a chance to replace the {{hash}} with actual URL, the
   * link will be broken and will most likely return a 404 error.
   * The `ng-href` solves this problem by placing the `href` in the
   * `ng-` namespace.
   *
   * The buggy way to write it:
   * <pre>
   * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
   * </pre>
   *
   * The correct way to write it:
   * <pre>
   * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
   * </pre>
   *
   * @element A
   * @param {template} ng-href any string which can contain `{{}}` markup.
   *
   * @example
   * This example uses `link` variable inside `href` attribute:
      <doc:example>
        <doc:source>
          <input ng-model="value" /><br />
          <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
          <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
          <a id="link-3" ng-href="/{{'123'}}" ng-ext-link>link 3</a> (link, reload!)<br />
          <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
          <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
          <a id="link-6" ng-href="/{{value}}" ng-ext-link>link</a> (link, change hash)
        </doc:source>
        <doc:scenario>
          it('should execute ng-click but not reload when href without value', function() {
            element('#link-1').click();
            expect(input('value').val()).toEqual('1');
            expect(element('#link-1').attr('href')).toBe("");
          });
  
          it('should execute ng-click but not reload when href empty string', function() {
            element('#link-2').click();
            expect(input('value').val()).toEqual('2');
            expect(element('#link-2').attr('href')).toBe("");
          });
  
          it('should execute ng-click and change url when ng-href specified', function() {
            expect(element('#link-3').attr('href')).toBe("/123");
  
            element('#link-3').click();
            expect(browser().window().path()).toEqual('/123');
          });
  
          it('should execute ng-click but not reload when href empty string and name specified', function() {
            element('#link-4').click();
            expect(input('value').val()).toEqual('4');
            expect(element('#link-4').attr('href')).toBe("");
          });
  
          it('should execute ng-click but not reload when no href but name specified', function() {
            element('#link-5').click();
            expect(input('value').val()).toEqual('5');
            expect(element('#link-5').attr('href')).toBe("");
          });
  
          it('should only change url when only ng-href', function() {
            input('value').enter('6');
            expect(element('#link-6').attr('href')).toBe("/6");
  
            element('#link-6').click();
            expect(browser().window().path()).toEqual('/6');
          });
        </doc:scenario>
      </doc:example>
   */
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-src
   * @restrict A
   *
   * @description
   * Using <angular/> markup like `{{hash}}` in a `src` attribute doesn't
   * work right: The browser will fetch from the URL with the literal
   * text `{{hash}}` until <angular/> replaces the expression inside
   * `{{hash}}`. The `ng-src` attribute solves this problem by placing
   *  the `src` attribute in the `ng-` namespace.
   *
   * The buggy way to write it:
   * <pre>
   * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
   * </pre>
   *
   * The correct way to write it:
   * <pre>
   * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
   * </pre>
   *
   * @element IMG
   * @param {template} ng-src any string which can contain `{{}}` markup.
   */
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-disabled
   * @restrict A
   *
   * @description
   *
   * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
   * <pre>
   * <div ng-init="scope = { isDisabled: false }">
   *  <button disabled="{{scope.isDisabled}}">Disabled</button>
   * </div>
   * </pre>
   *
   * The HTML specs do not require browsers to preserve the special attributes such as disabled.
   * (The presence of them means true and absence means false)
   * This prevents the angular compiler from correctly retrieving the binding expression.
   * To solve this problem, we introduce ng-disabled.
   *
   * @example
      <doc:example>
        <doc:source>
          Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
          <button ng-model="button" ng-disabled="checked">Button</button>
        </doc:source>
        <doc:scenario>
          it('should toggle button', function() {
            expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
            input('checked').check();
            expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
          });
        </doc:scenario>
      </doc:example>
   *
   * @element INPUT
   * @param {string} expression Angular expression that will be evaluated.
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-checked
   * @restrict A
   *
   * @description
   * The HTML specs do not require browsers to preserve the special attributes such as checked.
   * (The presence of them means true and absence means false)
   * This prevents the angular compiler from correctly retrieving the binding expression.
   * To solve this problem, we introduce ng-checked.
   * @example
      <doc:example>
        <doc:source>
          Check me to check both: <input type="checkbox" ng-model="master"><br/>
          <input id="checkSlave" type="checkbox" ng-checked="master">
        </doc:source>
        <doc:scenario>
          it('should check both checkBoxes', function() {
            expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
            input('master').check();
            expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
          });
        </doc:scenario>
      </doc:example>
   *
   * @element INPUT
   * @param {string} expression Angular expression that will be evaluated.
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-multiple
   * @restrict A
   *
   * @description
   * The HTML specs do not require browsers to preserve the special attributes such as multiple.
   * (The presence of them means true and absence means false)
   * This prevents the angular compiler from correctly retrieving the binding expression.
   * To solve this problem, we introduce ng-multiple.
   *
   * @example
       <doc:example>
         <doc:source>
           Check me check multiple: <input type="checkbox" ng-model="checked"><br/>
           <select id="select" ng-multiple="checked">
             <option>Misko</option>
             <option>Igor</option>
             <option>Vojta</option>
             <option>Di</option>
           </select>
         </doc:source>
         <doc:scenario>
           it('should toggle multiple', function() {
             expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
             input('checked').check();
             expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
           });
         </doc:scenario>
       </doc:example>
   *
   * @element SELECT
   * @param {string} expression Angular expression that will be evaluated.
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-readonly
   * @restrict A
   *
   * @description
   * The HTML specs do not require browsers to preserve the special attributes such as readonly.
   * (The presence of them means true and absence means false)
   * This prevents the angular compiler from correctly retrieving the binding expression.
   * To solve this problem, we introduce ng-readonly.
   * @example
      <doc:example>
        <doc:source>
          Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
          <input type="text" ng-readonly="checked" value="I'm Angular"/>
        </doc:source>
        <doc:scenario>
          it('should toggle readonly attr', function() {
            expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
            input('checked').check();
            expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
          });
        </doc:scenario>
      </doc:example>
   *
   * @element INPUT
   * @param {string} expression Angular expression that will be evaluated.
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-selected
   * @restrict A
   *
   * @description
   * The HTML specs do not require browsers to preserve the special attributes such as selected.
   * (The presence of them means true and absence means false)
   * This prevents the angular compiler from correctly retrieving the binding expression.
   * To solve this problem, we introduce ng-selected.
   * @example
      <doc:example>
        <doc:source>
          Check me to select: <input type="checkbox" ng-model="selected"><br/>
          <select>
            <option>Hello!</option>
            <option id="greet" ng-selected="selected">Greetings!</option>
          </select>
        </doc:source>
        <doc:scenario>
          it('should select Greetings!', function() {
            expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
            input('selected').check();
            expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
          });
        </doc:scenario>
      </doc:example>
   *
   * @element OPTION
   * @param {string} expression Angular expression that will be evaluated.
   */
  
  
  var ngAttributeAliasDirectives = {};
  
  
  // boolean attrs are evaluated
  forEach(BOOLEAN_ATTR, function(propName, attrName) {
    var normalized = directiveNormalize('ng-' + attrName);
    ngAttributeAliasDirectives[normalized] = function() {
      return {
        priority: 100,
        compile: function(tpl, attr) {
          return function(scope, element, attr) {
            attr.$$observers[attrName] = [];
            scope.$watch(attr[normalized], function(value) {
              attr.$set(attrName, !!value);
            });
          };
        }
      };
    };
  });
  
  
  // ng-src, ng-href are interpolated
  forEach(['src', 'href'], function(attrName) {
    var normalized = directiveNormalize('ng-' + attrName);
    ngAttributeAliasDirectives[normalized] = function() {
      return {
        priority: 99, // it needs to run after the attributes are interpolated
        compile: function(tpl, attr) {
          return function(scope, element, attr) {
            var value = attr[normalized];
            if (value == undefined) {
              // undefined value means that the directive is being interpolated
              // so just register observer
              attr.$$observers[attrName] = [];
              attr.$observe(normalized, function(value) {
                attr.$set(attrName, value);
              });
            } else {
              // value present means that no interpolation, so copy to native attribute.
              attr.$set(attrName, value);
            }
          };
        }
      };
    };
  });
  
  var nullFormCtrl = {
    $addControl: noop,
    $removeControl: noop,
    $setValidity: noop,
    $setDirty: noop
  }
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$compileProvider.directive.form.FormController
   *
   * @property {boolean} $pristine True if user has not interacted with the form yet.
   * @property {boolean} $dirty True if user has already interacted with the form.
   * @property {boolean} $valid True if all of the containg forms and controls are valid.
   * @property {boolean} $invalid True if at least one containing control or form is invalid.
   *
   * @property {Object} $error Is an object hash, containing references to all invalid controls or
   *  forms, where:
   *
   *  - keys are validation tokens (error names) â€” such as `REQUIRED`, `URL` or `EMAIL`),
   *  - values are arrays of controls or forms that are invalid with given error.
   *
   * @description
   * `FormController` keeps track of all its controls and nested forms as well as state of them,
   * such as being valid/invalid or dirty/pristine.
   *
   * Each {@link angular.module.ng.$compileProvider.directive.form form} directive creates an instance
   * of `FormController`.
   *
   */
  //asks for $scope to fool the BC controller module
  FormController.$inject = ['$element', '$attrs', '$scope'];
  function FormController(element, attrs) {
    var form = this,
        parentForm = element.parent().controller('form') || nullFormCtrl,
        invalidCount = 0, // used to easily determine if we are valid
        errors = form.$error = {};
  
    // init state
    form.$name = attrs.name;
    form.$dirty = false;
    form.$pristine = true;
    form.$valid = true;
    form.$invalid = false;
  
    parentForm.$addControl(form);
  
    // Setup initial state of the control
    element.addClass(PRISTINE_CLASS);
    toggleValidCss(true);
  
    // convenience method for easy toggling of classes
    function toggleValidCss(isValid, validationErrorKey) {
      validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
      element.
        removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
        addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
    }
  
    form.$addControl = function(control) {
      if (control.$name && !form.hasOwnProperty(control.$name)) {
        form[control.$name] = control;
      }
    };
  
    form.$removeControl = function(control) {
      if (control.$name && form[control.$name] === control) {
        delete form[control.$name];
      }
      forEach(errors, function(queue, validationToken) {
        form.$setValidity(validationToken, true, control);
      });
    };
  
    form.$setValidity = function(validationToken, isValid, control) {
      var queue = errors[validationToken];
  
      if (isValid) {
        if (queue) {
          arrayRemove(queue, control);
          if (!queue.length) {
            invalidCount--;
            if (!invalidCount) {
              toggleValidCss(isValid);
              form.$valid = true;
              form.$invalid = false;
            }
            errors[validationToken] = false;
            toggleValidCss(true, validationToken);
            parentForm.$setValidity(validationToken, true, form);
          }
        }
  
      } else {
        if (!invalidCount) {
          toggleValidCss(isValid);
        }
        if (queue) {
          if (includes(queue, control)) return;
        } else {
          errors[validationToken] = queue = [];
          invalidCount++;
          toggleValidCss(false, validationToken);
          parentForm.$setValidity(validationToken, false, form);
        }
        queue.push(control);
  
        form.$valid = false;
        form.$invalid = true;
      }
    };
  
    form.$setDirty = function() {
      element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
      form.$dirty = true;
      form.$pristine = false;
    };
  
  }
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-form
   * @restrict EAC
   *
   * @description
   * Nestable alias of {@link angular.module.ng.$compileProvider.directive.form `form`} directive. HTML
   * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
   * sub-group of controls needs to be determined.
   *
   * @param {string=} ng-form|name Name of the form. If specified, the form controller will be published into
   *                       related scope, under this name.
   *
   */
  
   /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.form
   * @restrict E
   *
   * @description
   * Directive that instantiates
   * {@link angular.module.ng.$compileProvider.directive.form.FormController FormController}.
   *
   * If `name` attribute is specified, the form controller is published onto the current scope under
   * this name.
   *
   * # Alias: {@link angular.module.ng.$compileProvider.directive.ng-form `ng-form`}
   *
   * In angular forms can be nested. This means that the outer form is valid when all of the child
   * forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
   * reason angular provides {@link angular.module.ng.$compileProvider.directive.ng-form `ng-form`} alias
   * which behaves identical to `<form>` but allows form nesting.
   *
   *
   * # CSS classes
   *  - `ng-valid` Is set if the form is valid.
   *  - `ng-invalid` Is set if the form is invalid.
   *  - `ng-pristine` Is set if the form is pristine.
   *  - `ng-dirty` Is set if the form is dirty.
   *
   *
   * # Submitting a form and preventing default action
   *
   * Since the role of forms in client-side Angular applications is different than in classical
   * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
   * page reload that sends the data to the server. Instead some javascript logic should be triggered
   * to handle the form submission in application specific way.
   *
   * For this reason, Angular prevents the default action (form submission to the server) unless the
   * `<form>` element has an `action` attribute specified.
   *
   * You can use one of the following two ways to specify what javascript method should be called when
   * a form is submitted:
   *
   * - ng-submit on the form element (add link to ng-submit)
   * - ng-click on the first button or input field of type submit (input[type=submit])
   *
   * To prevent double execution of the handler, use only one of ng-submit or ng-click. This is
   * because of the following form submission rules coming from the html spec:
   *
   * - If a form has only one input field then hitting enter in this field triggers form submit
   * (`ng-submit`)
   * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
   * doesn't trigger submit
   * - if a form has one or more input fields and one or more buttons or input[type=submit] then
   * hitting enter in any of the input fields will trigger the click handler on the *first* button or
   * input[type=submit] (`ng-click`) *and* a submit handler on the enclosing form (`ng-submit`)
   *
   * @param {string=} name Name of the form. If specified, the form controller will be published into
   *                       related scope, under this name.
   *
   * @example
      <doc:example>
        <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.userType = 'guest';
           }
         </script>
         <form name="myForm" ng-controller="Ctrl">
           userType: <input name="input" ng-model="userType" required>
           <span class="error" ng-show="myForm.input.$error.REQUIRED">Required!</span><br>
           <tt>userType = {{userType}}</tt><br>
           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
           <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
           <tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
          </form>
        </doc:source>
        <doc:scenario>
          it('should initialize to model', function() {
           expect(binding('userType')).toEqual('guest');
           expect(binding('myForm.input.$valid')).toEqual('true');
          });
  
          it('should be invalid if empty', function() {
           input('userType').enter('');
           expect(binding('userType')).toEqual('');
           expect(binding('myForm.input.$valid')).toEqual('false');
          });
        </doc:scenario>
      </doc:example>
   */
  var formDirectiveDir = {
    name: 'form',
    restrict: 'E',
    controller: FormController,
    compile: function() {
      return {
        pre: function(scope, formElement, attr, controller) {
          if (!attr.action) {
            formElement.bind('submit', function(event) {
              event.preventDefault();
            });
          }
  
          var parentFormCtrl = formElement.parent().controller('form'),
              alias = attr.name || attr.ngForm;
  
          if (alias) {
            scope[alias] = controller;
          }
          if (parentFormCtrl) {
            formElement.bind('$destroy', function() {
              parentFormCtrl.$removeControl(controller);
              if (alias) {
                scope[alias] = undefined;
              }
              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
            });
          }
        }
      };
    }
  };
  
  var formDirective = valueFn(formDirectiveDir);
  var ngFormDirective = valueFn(extend(copy(formDirectiveDir), {restrict: 'EAC'}));
  
  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
  var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
  
  var inputType = {
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.text
     *
     * @description
     * Standard HTML text input with angular data binding.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} required Sets `required` validation error key if the value is not entered.
     * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
     *    minlength.
     * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
     *    maxlength.
     * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
     *    patterns defined as scope expressions.
     * @param {string=} ng-change Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.text = 'guest';
               $scope.word = /^\w*$/;
             }
           </script>
           <form name="myForm" ng-controller="Ctrl">
             Single word: <input type="text" name="input" ng-model="text"
                                 ng-pattern="word" required>
             <span class="error" ng-show="myForm.input.$error.required">
               Required!</span>
             <span class="error" ng-show="myForm.input.$error.pattern">
               Single word only!</span>
  
             <tt>text = {{text}}</tt><br/>
             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
            </form>
          </doc:source>
          <doc:scenario>
            it('should initialize to model', function() {
              expect(binding('text')).toEqual('guest');
              expect(binding('myForm.input.$valid')).toEqual('true');
            });
  
            it('should be invalid if empty', function() {
              input('text').enter('');
              expect(binding('text')).toEqual('');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
  
            it('should be invalid if multi word', function() {
              input('text').enter('hello world');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
          </doc:scenario>
        </doc:example>
     */
    'text': textInputType,
  
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.number
     *
     * @description
     * Text input with number validation and transformation. Sets the `number` validation
     * error if not a valid number.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
     * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
     * @param {string=} required Sets `required` validation error key if the value is not entered.
     * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
     *    minlength.
     * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
     *    maxlength.
     * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
     *    patterns defined as scope expressions.
     * @param {string=} ng-change Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.value = 12;
             }
           </script>
           <form name="myForm" ng-controller="Ctrl">
             Number: <input type="number" name="input" ng-model="value"
                            min="0" max="99" required>
             <span class="error" ng-show="myForm.list.$error.required">
               Required!</span>
             <span class="error" ng-show="myForm.list.$error.number">
               Not valid number!</span>
             <tt>value = {{value}}</tt><br/>
             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
            </form>
          </doc:source>
          <doc:scenario>
            it('should initialize to model', function() {
             expect(binding('value')).toEqual('12');
             expect(binding('myForm.input.$valid')).toEqual('true');
            });
  
            it('should be invalid if empty', function() {
             input('value').enter('');
             expect(binding('value')).toEqual('');
             expect(binding('myForm.input.$valid')).toEqual('false');
            });
  
            it('should be invalid if over max', function() {
             input('value').enter('123');
             expect(binding('value')).toEqual('');
             expect(binding('myForm.input.$valid')).toEqual('false');
            });
          </doc:scenario>
        </doc:example>
     */
    'number': numberInputType,
  
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.url
     *
     * @description
     * Text input with URL validation. Sets the `url` validation error key if the content is not a
     * valid URL.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} required Sets `required` validation error key if the value is not entered.
     * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
     *    minlength.
     * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
     *    maxlength.
     * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
     *    patterns defined as scope expressions.
     * @param {string=} ng-change Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.text = 'http://google.com';
             }
           </script>
           <form name="myForm" ng-controller="Ctrl">
             URL: <input type="url" name="input" ng-model="text" required>
             <span class="error" ng-show="myForm.input.$error.required">
               Required!</span>
             <span class="error" ng-show="myForm.input.$error.url">
               Not valid url!</span>
             <tt>text = {{text}}</tt><br/>
             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
             <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
            </form>
          </doc:source>
          <doc:scenario>
            it('should initialize to model', function() {
              expect(binding('text')).toEqual('http://google.com');
              expect(binding('myForm.input.$valid')).toEqual('true');
            });
  
            it('should be invalid if empty', function() {
              input('text').enter('');
              expect(binding('text')).toEqual('');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
  
            it('should be invalid if not url', function() {
              input('text').enter('xxx');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
          </doc:scenario>
        </doc:example>
     */
    'url': urlInputType,
  
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.email
     *
     * @description
     * Text input with email validation. Sets the `email` validation error key if not a valid email
     * address.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} required Sets `required` validation error key if the value is not entered.
     * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
     *    minlength.
     * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
     *    maxlength.
     * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
     *    patterns defined as scope expressions.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.text = 'me@example.com';
             }
           </script>
             <form name="myForm" ng-controller="Ctrl">
               Email: <input type="email" name="input" ng-model="text" required>
               <span class="error" ng-show="myForm.input.$error.required">
                 Required!</span>
               <span class="error" ng-show="myForm.input.$error.email">
                 Not valid email!</span>
               <tt>text = {{text}}</tt><br/>
               <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
               <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
               <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
               <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
               <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
             </form>
          </doc:source>
          <doc:scenario>
            it('should initialize to model', function() {
              expect(binding('text')).toEqual('me@example.com');
              expect(binding('myForm.input.$valid')).toEqual('true');
            });
  
            it('should be invalid if empty', function() {
              input('text').enter('');
              expect(binding('text')).toEqual('');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
  
            it('should be invalid if not email', function() {
              input('text').enter('xxx');
              expect(binding('myForm.input.$valid')).toEqual('false');
            });
          </doc:scenario>
        </doc:example>
     */
    'email': emailInputType,
  
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.radio
     *
     * @description
     * HTML radio button.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string} value The value to which the expression should be set when selected.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} ng-change Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.color = 'blue';
             }
           </script>
           <form name="myForm" ng-controller="Ctrl">
             <input type="radio" ng-model="color" value="red">  Red <br/>
             <input type="radio" ng-model="color" value="green"> Green <br/>
             <input type="radio" ng-model="color" value="blue"> Blue <br/>
             <tt>color = {{color}}</tt><br/>
            </form>
          </doc:source>
          <doc:scenario>
            it('should change state', function() {
              expect(binding('color')).toEqual('blue');
  
              input('color').select('red');
              expect(binding('color')).toEqual('red');
            });
          </doc:scenario>
        </doc:example>
     */
    'radio': radioInputType,
  
  
    /**
     * @ngdoc inputType
     * @name angular.module.ng.$compileProvider.directive.input.checkbox
     *
     * @description
     * HTML checkbox.
     *
     * @param {string} ng-model Assignable angular expression to data-bind to.
     * @param {string=} name Property name of the form under which the control is published.
     * @param {string=} ng-true-value The value to which the expression should be set when selected.
     * @param {string=} ng-false-value The value to which the expression should be set when not selected.
     * @param {string=} ng-change Angular expression to be executed when input changes due to user
     *    interaction with the input element.
     *
     * @example
        <doc:example>
          <doc:source>
           <script>
             function Ctrl($scope) {
               $scope.value1 = true;
               $scope.value2 = 'YES'
             }
           </script>
           <form name="myForm" ng-controller="Ctrl">
             Value1: <input type="checkbox" ng-model="value1"> <br/>
             Value2: <input type="checkbox" ng-model="value2"
                            ng-true-value="YES" ng-false-value="NO"> <br/>
             <tt>value1 = {{value1}}</tt><br/>
             <tt>value2 = {{value2}}</tt><br/>
            </form>
          </doc:source>
          <doc:scenario>
            it('should change state', function() {
              expect(binding('value1')).toEqual('true');
              expect(binding('value2')).toEqual('YES');
  
              input('value1').check();
              input('value2').check();
              expect(binding('value1')).toEqual('false');
              expect(binding('value2')).toEqual('NO');
            });
          </doc:scenario>
        </doc:example>
     */
    'checkbox': checkboxInputType,
  
    'hidden': noop,
    'button': noop,
    'submit': noop,
    'reset': noop
  };
  
  
  function isEmpty(value) {
    return isUndefined(value) || value === '' || value === null || value !== value;
  }
  
  
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  
    var listener = function() {
      var value = trim(element.val());
  
      if (ctrl.$viewValue !== value) {
        scope.$apply(function() {
          ctrl.$setViewValue(value);
        });
      }
    };
  
    // if the browser does support "input" event, we are fine
    if ($sniffer.hasEvent('input')) {
      element.bind('input', listener);
    } else {
      var timeout;
  
      element.bind('keydown', function(event) {
        var key = event.keyCode;
  
        // ignore
        //    command            modifiers                   arrows
        if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
  
        if (!timeout) {
          timeout = $browser.defer(function() {
            listener();
            timeout = null;
          });
        }
      });
  
      // if user paste into input using mouse, we need "change" event to catch it
      element.bind('change', listener);
    }
  
  
    ctrl.$render = function() {
      element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
    };
  
    // pattern validator
    var pattern = attr.ngPattern,
        patternValidator;
  
    var validate = function(regexp, value) {
      if (isEmpty(value) || regexp.test(value)) {
        ctrl.$setValidity('pattern', true);
        return value;
      } else {
        ctrl.$setValidity('pattern', false);
        return undefined;
      }
    };
  
    if (pattern) {
      if (pattern.match(/^\/(.*)\/$/)) {
        pattern = new RegExp(pattern.substr(1, pattern.length - 2));
        patternValidator = function(value) {
          return validate(pattern, value)
        };
      } else {
        patternValidator = function(value) {
          var patternObj = scope.$eval(pattern);
  
          if (!patternObj || !patternObj.test) {
            throw new Error('Expected ' + pattern + ' to be a RegExp but was ' + patternObj);
          }
          return validate(patternObj, value);
        };
      }
  
      ctrl.$formatters.push(patternValidator);
      ctrl.$parsers.push(patternValidator);
    }
  
    // min length validator
    if (attr.ngMinlength) {
      var minlength = int(attr.ngMinlength);
      var minLengthValidator = function(value) {
        if (!isEmpty(value) && value.length < minlength) {
          ctrl.$setValidity('minlength', false);
          return undefined;
        } else {
          ctrl.$setValidity('minlength', true);
          return value;
        }
      };
  
      ctrl.$parsers.push(minLengthValidator);
      ctrl.$formatters.push(minLengthValidator);
    }
  
    // max length validator
    if (attr.ngMaxlength) {
      var maxlength = int(attr.ngMaxlength);
      var maxLengthValidator = function(value) {
        if (!isEmpty(value) && value.length > maxlength) {
          ctrl.$setValidity('maxlength', false);
          return undefined;
        } else {
          ctrl.$setValidity('maxlength', true);
          return value;
        }
      };
  
      ctrl.$parsers.push(maxLengthValidator);
      ctrl.$formatters.push(maxLengthValidator);
    }
  };
  
  function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
    textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  
    ctrl.$parsers.push(function(value) {
      var empty = isEmpty(value);
      if (empty || NUMBER_REGEXP.test(value)) {
        ctrl.$setValidity('number', true);
        return value === '' ? null : (empty ? value : parseFloat(value));
      } else {
        ctrl.$setValidity('number', false);
        return undefined;
      }
    });
  
    ctrl.$formatters.push(function(value) {
      return isEmpty(value) ? '' : '' + value;
    });
  
    if (attr.min) {
      var min = parseFloat(attr.min);
      var minValidator = function(value) {
        if (!isEmpty(value) && value < min) {
          ctrl.$setValidity('min', false);
          return undefined;
        } else {
          ctrl.$setValidity('min', true);
          return value;
        }
      };
  
      ctrl.$parsers.push(minValidator);
      ctrl.$formatters.push(minValidator);
    }
  
    if (attr.max) {
      var max = parseFloat(attr.max);
      var maxValidator = function(value) {
        if (!isEmpty(value) && value > max) {
          ctrl.$setValidity('max', false);
          return undefined;
        } else {
          ctrl.$setValidity('max', true);
          return value;
        }
      };
  
      ctrl.$parsers.push(maxValidator);
      ctrl.$formatters.push(maxValidator);
    }
  
    ctrl.$formatters.push(function(value) {
  
      if (isEmpty(value) || isNumber(value)) {
        ctrl.$setValidity('number', true);
        return value;
      } else {
        ctrl.$setValidity('number', false);
        return undefined;
      }
    });
  }
  
  function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
    textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  
    var urlValidator = function(value) {
      if (isEmpty(value) || URL_REGEXP.test(value)) {
        ctrl.$setValidity('url', true);
        return value;
      } else {
        ctrl.$setValidity('url', false);
        return undefined;
      }
    };
  
    ctrl.$formatters.push(urlValidator);
    ctrl.$parsers.push(urlValidator);
  }
  
  function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
    textInputType(scope, element, attr, ctrl, $sniffer, $browser);
  
    var emailValidator = function(value) {
      if (isEmpty(value) || EMAIL_REGEXP.test(value)) {
        ctrl.$setValidity('email', true);
        return value;
      } else {
        ctrl.$setValidity('email', false);
        return undefined;
      }
    };
  
    ctrl.$formatters.push(emailValidator);
    ctrl.$parsers.push(emailValidator);
  }
  
  function radioInputType(scope, element, attr, ctrl) {
    // correct the name
    element.attr('name', attr.id + '@' + attr.name);
  
    element.bind('click', function() {
      if (element[0].checked) {
        scope.$apply(function() {
          ctrl.$setViewValue(attr.value);
        });
      };
    });
  
    ctrl.$render = function() {
      var value = attr.value;
      element[0].checked = (value == ctrl.$viewValue);
    };
  
    attr.$observe('value', ctrl.$render);
  }
  
  function checkboxInputType(scope, element, attr, ctrl) {
    var trueValue = attr.ngTrueValue,
        falseValue = attr.ngFalseValue;
  
    if (!isString(trueValue)) trueValue = true;
    if (!isString(falseValue)) falseValue = false;
  
    element.bind('click', function() {
      scope.$apply(function() {
        ctrl.$setViewValue(element[0].checked);
      });
    });
  
    ctrl.$render = function() {
      element[0].checked = ctrl.$viewValue;
    };
  
    ctrl.$formatters.push(function(value) {
      return value === trueValue;
    });
  
    ctrl.$parsers.push(function(value) {
      return value ? trueValue : falseValue;
    });
  }
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.textarea
   *
   * @description
   * HTML textarea element control with angular data-binding. The data-binding and validation
   * properties of this element are exactly the same as those of the
   * {@link angular.module.ng.$compileProvider.directive.input input element}.
   *
   * @param {string} ng-model Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ng-change Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.input
   * @restrict E
   *
   * @description
   * HTML input element control with angular data-binding. Input control follows HTML5 input types
   * and polyfills the HTML5 validation behavior for older browsers.
   *
   * @param {string} ng-model Assignable angular expression to data-bind to.
   * @param {string=} name Property name of the form under which the control is published.
   * @param {string=} required Sets `required` validation error key if the value is not entered.
   * @param {number=} ng-minlength Sets `minlength` validation error key if the value is shorter than
   *    minlength.
   * @param {number=} ng-maxlength Sets `maxlength` validation error key if the value is longer than
   *    maxlength.
   * @param {string=} ng-pattern Sets `pattern` validation error key if the value does not match the
   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
   *    patterns defined as scope expressions.
   * @param {string=} ng-change Angular expression to be executed when input changes due to user
   *    interaction with the input element.
   *
   * @example
      <doc:example>
        <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.user = {name: 'guest', last: 'visitor'};
           }
         </script>
         <div ng-controller="Ctrl">
           <form name="myForm">
             User name: <input type="text" name="userName" ng-model="user.name" required>
             <span class="error" ng-show="myForm.userName.$error.required">
               Required!</span><br>
             Last name: <input type="text" name="lastName" ng-model="user.last"
               ng-minlength="3" ng-maxlength="10">
             <span class="error" ng-show="myForm.lastName.$error.minlength">
               Too short!</span>
             <span class="error" ng-show="myForm.lastName.$error.maxlength">
               Too long!</span><br>
           </form>
           <hr>
           <tt>user = {{user}}</tt><br/>
           <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
           <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
           <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
           <tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br>
           <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
           <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
           <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
         </div>
        </doc:source>
        <doc:scenario>
          it('should initialize to model', function() {
            expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
            expect(binding('myForm.userName.$valid')).toEqual('true');
            expect(binding('myForm.$valid')).toEqual('true');
          });
  
          it('should be invalid if empty when required', function() {
            input('user.name').enter('');
            expect(binding('user')).toEqual('{"last":"visitor"}');
            expect(binding('myForm.userName.$valid')).toEqual('false');
            expect(binding('myForm.$valid')).toEqual('false');
          });
  
          it('should be valid if empty when min length is set', function() {
            input('user.last').enter('');
            expect(binding('user')).toEqual('{"name":"guest","last":""}');
            expect(binding('myForm.lastName.$valid')).toEqual('true');
            expect(binding('myForm.$valid')).toEqual('true');
          });
  
          it('should be invalid if less than required min length', function() {
            input('user.last').enter('xx');
            expect(binding('user')).toEqual('{"name":"guest"}');
            expect(binding('myForm.lastName.$valid')).toEqual('false');
            expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
            expect(binding('myForm.$valid')).toEqual('false');
          });
  
          it('should be invalid if longer than max length', function() {
            input('user.last').enter('some ridiculously long name');
            expect(binding('user'))
              .toEqual('{"name":"guest"}');
            expect(binding('myForm.lastName.$valid')).toEqual('false');
            expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
            expect(binding('myForm.$valid')).toEqual('false');
          });
        </doc:scenario>
      </doc:example>
   */
  var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
    return {
      restrict: 'E',
      require: '?ngModel',
      link: function(scope, element, attr, ctrl) {
        if (ctrl) {
          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
                                                              $browser);
        }
      }
    };
  }];
  
  var VALID_CLASS = 'ng-valid',
      INVALID_CLASS = 'ng-invalid',
      PRISTINE_CLASS = 'ng-pristine',
      DIRTY_CLASS = 'ng-dirty';
  
  /**
   * @ngdoc object
   * @name angular.module.ng.$compileProvider.directive.ng-model.NgModelController
   *
   * @property {string} $viewValue Actual string value in the view.
   * @property {*} $modelValue The value in the model, that the control is bound to.
   * @property {Array.<Function>} $parsers Whenever the control reads value from the DOM, it executes
   *     all of these functions to sanitize / convert the value as well as validate.
   *
   * @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
   *     these functions to convert the value as well as validate.
   *
   * @property {Object} $error An bject hash with all errors as keys.
   *
   * @property {boolean} $pristine True if user has not interacted with the control yet.
   * @property {boolean} $dirty True if user has already interacted with the control.
   * @property {boolean} $valid True if there is no error.
   * @property {boolean} $invalid True if at least one error on the control.
   *
   * @description
   *
   */
  var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$element',
      function($scope, $exceptionHandler, $attr, ngModel, $element) {
    this.$viewValue = Number.NaN;
    this.$modelValue = Number.NaN;
    this.$parsers = [];
    this.$formatters = [];
    this.$viewChangeListeners = [];
    this.$pristine = true;
    this.$dirty = false;
    this.$valid = true;
    this.$invalid = false;
    this.$render = noop;
    this.$name = $attr.name;
  
    var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
        invalidCount = 0, // used to easily determine if we are valid
        $error = this.$error = {}; // keep invalid keys here
  
  
    // Setup initial state of the control
    $element.addClass(PRISTINE_CLASS);
    toggleValidCss(true);
  
    // convenience method for easy toggling of classes
    function toggleValidCss(isValid, validationErrorKey) {
      validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
      $element.
        removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
        addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
    }
  
    /**
     * @ngdoc function
     * @name angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$setValidity
     * @methodOf angular.module.ng.$compileProvider.directive.ng-model.NgModelController
     *
     * @description
     * Change the validity state, and notifies the form when the control changes validity. (i.e. it
     * does not notify form if given validator is already marked as invalid).
     *
     * This method should be called by validators - i.e. the parser or formatter functions.
     *
     * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
     *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
     *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
     *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
     *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
     * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
     */
    this.$setValidity = function(validationErrorKey, isValid) {
      if ($error[validationErrorKey] === !isValid) return;
  
      if (isValid) {
        if ($error[validationErrorKey]) invalidCount--;
        if (!invalidCount) {
          toggleValidCss(true);
          this.$valid = true;
          this.$invalid = false;
        }
      } else {
        toggleValidCss(false)
        this.$invalid = true;
        this.$valid = false;
        invalidCount++;
      }
  
      $error[validationErrorKey] = !isValid;
      toggleValidCss(isValid, validationErrorKey);
  
      parentForm.$setValidity(validationErrorKey, isValid, this);
    };
  
  
    /**
     * @ngdoc function
     * @name angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$setViewValue
     * @methodOf angular.module.ng.$compileProvider.directive.ng-model.NgModelController
     *
     * @description
     * Read a value from view.
     *
     * This method should be called from within a DOM event handler.
     * For example {@link angular.module.ng.$compileProvider.directive.input input} or
     * {@link angular.module.ng.$compileProvider.directive.select select} directives call it.
     *
     * It internally calls all `formatters` and if resulted value is valid, updates the model and
     * calls all registered change listeners.
     *
     * @param {string} value Value from the view.
     */
    this.$setViewValue = function(value) {
      this.$viewValue = value;
  
      // change to dirty
      if (this.$pristine) {
        this.$dirty = true;
        this.$pristine = false;
        $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
        parentForm.$setDirty();
      }
  
      forEach(this.$parsers, function(fn) {
        value = fn(value);
      });
  
      if (this.$modelValue !== value) {
        this.$modelValue = value;
        ngModel(value);
        forEach(this.$viewChangeListeners, function(listener) {
          try {
            listener();
          } catch(e) {
            $exceptionHandler(e);
          }
        })
      }
    };
  
    // model -> value
    var ctrl = this;
    $scope.$watch(function() {
      return ngModel();
    }, function(value) {
  
      // ignore change from view
      if (ctrl.$modelValue === value) return;
  
      var formatters = ctrl.$formatters,
          idx = formatters.length;
  
      ctrl.$modelValue = value;
      while(idx--) {
        value = formatters[idx](value);
      }
  
      if (ctrl.$viewValue !== value) {
        ctrl.$viewValue = value;
        ctrl.$render();
      }
    });
  }];
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-model
   *
   * @element input
   *
   * @description
   * Is directive that tells Angular to do two-way data binding. It works together with `input`,
   * `select`, `textarea`. You can easily write your own directives to use `ng-model` as well.
   *
   * `ng-model` is responsible for:
   *
   * - binding the view into the model, which other directives such as `input`, `textarea` or `select`
   *   require,
   * - providing validation behavior (i.e. required, number, email, url),
   * - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
   * - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
   * - register the control with parent {@link angular.module.ng.$compileProvider.directive.form form}.
   *
   * For basic examples, how to use `ng-model`, see:
   *
   *  - {@link angular.module.ng.$compileProvider.directive.input input}
   *    - {@link angular.module.ng.$compileProvider.directive.input.text text}
   *    - {@link angular.module.ng.$compileProvider.directive.input.checkbox checkbox}
   *    - {@link angular.module.ng.$compileProvider.directive.input.radio radio}
   *    - {@link angular.module.ng.$compileProvider.directive.input.number number}
   *    - {@link angular.module.ng.$compileProvider.directive.input.email email}
   *    - {@link angular.module.ng.$compileProvider.directive.input.url url}
   *  - {@link angular.module.ng.$compileProvider.directive.select select}
   *  - {@link angular.module.ng.$compileProvider.directive.textarea textarea}
   *
   */
  var ngModelDirective = [function() {
    return {
      inject: {
        ngModel: 'accessor'
      },
      require: ['ngModel', '^?form'],
      controller: NgModelController,
      link: function(scope, element, attr, ctrls) {
        // notify others, especially parent forms
  
        var modelCtrl = ctrls[0],
            formCtrl = ctrls[1] || nullFormCtrl;
  
        formCtrl.$addControl(modelCtrl);
  
        element.bind('$destroy', function() {
          formCtrl.$removeControl(modelCtrl);
        });
      }
    };
  }];
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-change
   * @restrict E
   *
   * @description
   * Evaluate given expression when user changes the input.
   * The expression is not evaluated when the value change is coming from the model.
   *
   * Note, this directive requires `ng-model` to be present.
   *
   * @element input
   *
   * @example
   * <doc:example>
   *   <doc:source>
   *     <script>
   *       function Controller($scope) {
   *         $scope.counter = 0;
   *         $scope.change = function() {
   *           $scope.counter++;
   *         };
   *       }
   *     </script>
   *     <div ng-controller="Controller">
   *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
   *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
   *       <label for="ng-change-example2">Confirmed</label><br />
   *       debug = {{confirmed}}<br />
   *       counter = {{counter}}
   *     </div>
   *   </doc:source>
   *   <doc:scenario>
   *     it('should evaluate the expression if changing from view', function() {
   *       expect(binding('counter')).toEqual('0');
   *       element('#ng-change-example1').click();
   *       expect(binding('counter')).toEqual('1');
   *       expect(binding('confirmed')).toEqual('true');
   *     });
   *
   *     it('should not evaluate the expression if changing from model', function() {
   *       element('#ng-change-example2').click();
   *       expect(binding('counter')).toEqual('0');
   *       expect(binding('confirmed')).toEqual('true');
   *     });
   *   </doc:scenario>
   * </doc:example>
   */
  var ngChangeDirective = valueFn({
    require: 'ngModel',
    link: function(scope, element, attr, ctrl) {
      ctrl.$viewChangeListeners.push(function() {
        scope.$eval(attr.ngChange);
      });
    }
  });
  
  
  var requiredDirective = [function() {
    return {
      require: '?ngModel',
      link: function(scope, elm, attr, ctrl) {
        if (!ctrl) return;
  
        var validator = function(value) {
          if (attr.required && (isEmpty(value) || value === false)) {
            ctrl.$setValidity('required', false);
            return;
          } else {
            ctrl.$setValidity('required', true);
            return value;
          }
        };
  
        ctrl.$formatters.push(validator);
        ctrl.$parsers.unshift(validator);
  
        attr.$observe('required', function() {
          validator(ctrl.$viewValue);
        });
      }
    };
  }];
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-list
   *
   * @description
   * Text input that converts between comma-seperated string into an array of strings.
   *
   * @element input
   * @param {string=} ng-list optional delimiter that should be used to split the value. If
   *   specified in form `/something/` then the value will be converted into a regular expression.
   *
   * @example
      <doc:example>
        <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.names = ['igor', 'misko', 'vojta'];
           }
         </script>
         <form name="myForm" ng-controller="Ctrl">
           List: <input name="namesInput" ng-model="names" ng-list required>
           <span class="error" ng-show="myForm.list.$error.required">
             Required!</span>
           <tt>names = {{names}}</tt><br/>
           <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
           <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
          </form>
        </doc:source>
        <doc:scenario>
          it('should initialize to model', function() {
            expect(binding('names')).toEqual('["igor","misko","vojta"]');
            expect(binding('myForm.namesInput.$valid')).toEqual('true');
          });
  
          it('should be invalid if empty', function() {
            input('names').enter('');
            expect(binding('names')).toEqual('[]');
            expect(binding('myForm.namesInput.$valid')).toEqual('false');
          });
        </doc:scenario>
      </doc:example>
   */
  var ngListDirective = function() {
    return {
      require: 'ngModel',
      link: function(scope, element, attr, ctrl) {
        var match = /\/(.*)\//.exec(attr.ngList),
            separator = match && new RegExp(match[1]) || attr.ngList || ',';
  
        var parse = function(viewValue) {
          var list = [];
  
          if (viewValue) {
            forEach(viewValue.split(separator), function(value) {
              if (value) list.push(trim(value));
            });
          }
  
          return list;
        };
  
        ctrl.$parsers.push(parse);
        ctrl.$formatters.push(function(value) {
          if (isArray(value) && !equals(parse(ctrl.$viewValue), value)) {
            return value.join(', ');
          }
  
          return undefined;
        });
      }
    };
  };
  
  
  var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
  
  var ngValueDirective = [function() {
    return {
      priority: 100,
      compile: function(tpl, attr) {
        if (CONSTANT_VALUE_REGEXP.test(attr.ngValue)) {
          return function(scope) {
            attr.$set('value', scope.$eval(attr.ngValue));
          };
        } else {
          return function(scope, elm, attr) {
            attr.$$observers.value = [];
            scope.$watch(attr.ngValue, function(value) {
              attr.$set('value', value, false);
            });
          };
        }
      }
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-bind
   *
   * @description
   * The `ng-bind` 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 `ng-bind` directly, but instead you use the double curly markup like
   * `{{ expression }}` and let the Angular compiler transform it to
   * `<span ng-bind="expression"></span>` when the template is compiled.
   *
   * @element ANY
   * @param {expression} ng-bind {@link guide/dev_guide.expressions Expression} to evaluate.
   *
   * @example
   * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.name = 'Whirled';
           }
         </script>
         <div ng-controller="Ctrl">
           Enter name: <input type="text" ng-model="name"><br>
           Hello <span ng-bind="name"></span>!
         </div>
       </doc:source>
       <doc:scenario>
         it('should check ng-bind', function() {
           expect(using('.doc-example-live').binding('name')).toBe('Whirled');
           using('.doc-example-live').input('name').enter('world');
           expect(using('.doc-example-live').binding('name')).toBe('world');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngBindDirective = ngDirective(function(scope, element, attr) {
    element.addClass('ng-binding').data('$binding', attr.ngBind);
    scope.$watch(attr.ngBind, function(value) {
      element.text(value == undefined ? '' : value);
    });
  });
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-bind-html-unsafe
   *
   * @description
   * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
   * element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
   * {@link angular.module.ng.$compileProvider.directive.ng-bind-html ng-bind-html} directive is too
   * restrictive and when you absolutely trust the source of the content you are binding to.
   *
   * See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
   *
   * @element ANY
   * @param {expression} ng-bind-html-unsafe {@link guide/dev_guide.expressions Expression} to evaluate.
   */
  var ngBindHtmlUnsafeDirective = ngDirective(function(scope, element, attr) {
    element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
    scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
      element.html(value == undefined ? '' : value);
    });
  });
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-bind-html
   *
   * @description
   * Creates a binding that will sanitize the result of evaluating the `expression` with the
   * {@link angular.module.ng.$sanitize $sanitize} service and innerHTML the result into the current
   * element.
   *
   * See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
   *
   * @element ANY
   * @param {expression} ng-bind-html {@link guide/dev_guide.expressions Expression} to evaluate.
   */
  var ngBindHtmlDirective = ['$sanitize', function($sanitize) {
    return function(scope, element, attr) {
      element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
      scope.$watch(attr.ngBindHtml, function(value) {
        if (value = $sanitize(value)) {
          element.html(value);
        }
      });
    }
  }];
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-bind-template
   *
   * @description
   * The `ng-bind-template` attribute specifies that the element
   * text should be replaced with the template in ng-bind-template.
   * Unlike ng-bind the ng-bind-template can contain multiple `{{` `}}`
   * expressions. (This is required since some HTML elements
   * can not have SPAN elements such as TITLE, or OPTION to name a few.)
   *
   * @element ANY
   * @param {string} ng-bind-template template of form
   *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
   *
   * @example
   * Try it here: enter text in text box and watch the greeting change.
     <doc:example>
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.salutation = 'Hello';
             $scope.name = 'World';
           }
         </script>
         <div ng-controller="Ctrl">
          Salutation: <input type="text" ng-model="salutation"><br>
          Name: <input type="text" ng-model="name"><br>
          <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
         </div>
       </doc:source>
       <doc:scenario>
         it('should check ng-bind', function() {
           expect(using('.doc-example-live').binding('salutation')).
             toBe('Hello');
           expect(using('.doc-example-live').binding('name')).
             toBe('World');
           using('.doc-example-live').input('salutation').enter('Greetings');
           using('.doc-example-live').input('name').enter('user');
           expect(using('.doc-example-live').binding('salutation')).
             toBe('Greetings');
           expect(using('.doc-example-live').binding('name')).
             toBe('user');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
    return function(scope, element, attr) {
      // TODO: move this to scenario runner
      var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
      element.addClass('ng-binding').data('$binding', interpolateFn);
      attr.$observe('ngBindTemplate', function(value) {
        element.text(value);
      });
    }
  }];
  
  function classDirective(name, selector) {
    name = 'ngClass' + name;
    return ngDirective(function(scope, element, attr) {
      scope.$watch(attr[name], function(newVal, oldVal) {
        if (selector === true || scope.$index % 2 === selector) {
          if (oldVal && (newVal !== oldVal)) {
             if (isObject(oldVal) && !isArray(oldVal))
               oldVal = map(oldVal, function(v, k) { if (v) return k });
             element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
           }
           if (isObject(newVal) && !isArray(newVal))
              newVal = map(newVal, function(v, k) { if (v) return k });
           if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal);      }
      }, true);
    });
  }
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-class
   *
   * @description
   * The `ng-class` allows you to set CSS class on HTML 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 classes
   * new classes are added.
   *
   * @element ANY
   * @param {expression} ng-class {@link guide/dev_guide.expressions Expression} to eval. The result
   *   of the evaluation can be a string representing space delimited class
   *   names, an array, or a map of class names to boolean values.
   *
   * @example
     <doc:example>
       <doc:source>
        <input type="button" value="set" ng-click="myVar='ng-invalid'">
        <input type="button" value="clear" ng-click="myVar=''">
        <br>
        <span ng-class="myVar">Sample Text &nbsp;&nbsp;&nbsp;&nbsp;</span>
       </doc:source>
       <doc:scenario>
         it('should check ng-class', function() {
           expect(element('.doc-example-live span').prop('className')).not().
             toMatch(/ng-invalid/);
  
           using('.doc-example-live').element(':button:first').click();
  
           expect(element('.doc-example-live span').prop('className')).
             toMatch(/ng-invalid/);
  
           using('.doc-example-live').element(':button:last').click();
  
           expect(element('.doc-example-live span').prop('className')).not().
             toMatch(/ng-invalid/);
         });
       </doc:scenario>
     </doc:example>
   */
  var ngClassDirective = classDirective('', true);
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-class-odd
   *
   * @description
   * The `ng-class-odd` and `ng-class-even` works exactly as
   * {@link angular.module.ng.$compileProvider.directive.ng-class ng-class}, except it works in conjunction with `ng-repeat` and
   * takes affect only on odd (even) rows.
   *
   * This directive can be applied only within a scope of an
   * {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat}.
   *
   * @element ANY
   * @param {expression} ng-class-odd {@link guide/dev_guide.expressions Expression} to eval. The result
   *   of the evaluation can be a string representing space delimited class names or an array.
   *
   * @example
     <doc:example>
       <doc:source>
          <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
            <li ng-repeat="name in names">
             <span ng-class-odd="'ng-format-negative'"
                   ng-class-even="'ng-invalid'">
               {{name}} &nbsp; &nbsp; &nbsp;
             </span>
            </li>
          </ol>
       </doc:source>
       <doc:scenario>
         it('should check ng-class-odd and ng-class-even', function() {
           expect(element('.doc-example-live li:first span').prop('className')).
             toMatch(/ng-format-negative/);
           expect(element('.doc-example-live li:last span').prop('className')).
             toMatch(/ng-invalid/);
         });
       </doc:scenario>
     </doc:example>
   */
  var ngClassOddDirective = classDirective('Odd', 0);
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-class-even
   *
   * @description
   * The `ng-class-odd` and `ng-class-even` works exactly as
   * {@link angular.module.ng.$compileProvider.directive.ng-class ng-class}, except it works in
   * conjunction with `ng-repeat` and takes affect only on odd (even) rows.
   *
   * This directive can be applied only within a scope of an
   * {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat}.
   *
   * @element ANY
   * @param {expression} ng-class-even {@link guide/dev_guide.expressions Expression} to eval. The
   *   result of the evaluation can be a string representing space delimited class names or an array.
   *
   * @example
     <doc:example>
       <doc:source>
          <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
            <li ng-repeat="name in names">
             <span ng-class-odd="'odd'" ng-class-even="'even'">
               {{name}} &nbsp; &nbsp; &nbsp;
             </span>
            </li>
          </ol>
       </doc:source>
       <doc:scenario>
         it('should check ng-class-odd and ng-class-even', function() {
           expect(element('.doc-example-live li:first span').prop('className')).
             toMatch(/odd/);
           expect(element('.doc-example-live li:last span').prop('className')).
             toMatch(/even/);
         });
       </doc:scenario>
     </doc:example>
   */
  var ngClassEvenDirective = classDirective('Even', 1);
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-cloak
   *
   * @description
   * The `ng-cloak` 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
   * prefered in order to benefit from progressive rendering of the browser view.
   *
   * `ng-cloak` works in cooperation with a css rule that is embedded within `angular.js` and
   *  `angular.min.js` files. Following is the css rule:
   *
   * <pre>
   * [ng\:cloak], .ng-cloak {
   *   display: none;
   * }
   * </pre>
   *
   * 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 `ng-cloak` element attribute, which
   * makes the compiled element visible.
   *
   * For the best result, `angular.js` script must be loaded in the head section of the html file;
   * alternatively, the css rule (above) must be included in the external stylesheet of the
   * application.
   *
   * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
   * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
   * class `ng-cloak` in addition to `ng-cloak` directive as shown in the example below.
   *
   * @element ANY
   *
   * @example
     <doc:example>
       <doc:source>
          <div id="template1" ng-cloak>{{ 'hello' }}</div>
          <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
       </doc:source>
       <doc:scenario>
         it('should remove the template directive and css class', function() {
           expect(element('.doc-example-live #template1').attr('ng-cloak')).
             not().toBeDefined();
           expect(element('.doc-example-live #template2').attr('ng-cloak')).
             not().toBeDefined();
         });
       </doc:scenario>
     </doc:example>
   *
   */
  var ngCloakDirective = ngDirective({
    compile: function(element, attr) {
      attr.$set('ngCloak', undefined);
      element.removeClass('ng-cloak');
    }
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-controller
   *
   * @description
   * The `ng-controller` directive assigns behavior to a scope. This is a key aspect of how angular
   * supports the principles behind the Model-View-Controller design pattern.
   *
   * MVC components in angular:
   *
   * * Model â€” The Model is data in scope properties; scopes are attached to the DOM.
   * * View â€” The template (HTML with data bindings) is rendered into the View.
   * * Controller â€” The `ng-controller` directive specifies a Controller class; the class has
   *   methods that typically express the business logic behind the application.
   *
   * Note that an alternative way to define controllers is via the `{@link angular.module.ng.$route}`
   * service.
   *
   * @element ANY
   * @scope
   * @param {expression} ng-controller Name of a globally accessible constructor function or an
   *     {@link guide/dev_guide.expressions expression} that on the current scope evaluates to a
   *     constructor function.
   *
   * @example
   * Here is a simple form for editing user contact information. Adding, removing, clearing, and
   * greeting are methods declared on the controller (see source tab). These methods can
   * easily be called from the angular markup. Notice that the scope becomes the `this` for the
   * controller's instance. This allows for easy access to the view data from the controller. Also
   * notice that any changes to the data are automatically reflected in the View without the need
   * for a manual update.
     <doc:example>
       <doc:source>
        <script type="text/javascript">
          function SettingsController($scope) {
            $scope.name = "John Smith";
            $scope.contacts = [
              {type:'phone', value:'408 555 1212'},
              {type:'email', value:'john.smith@example.org'} ];
  
            $scope.greet = function() {
             alert(this.name);
            };
  
            $scope.addContact = function() {
             this.contacts.push({type:'email', value:'yourname@example.org'});
            };
  
            $scope.removeContact = function(contactToRemove) {
             var index = this.contacts.indexOf(contactToRemove);
             this.contacts.splice(index, 1);
            };
  
            $scope.clearContact = function(contact) {
             contact.type = 'phone';
             contact.value = '';
            };
          }
        </script>
        <div ng-controller="SettingsController">
          Name: <input type="text" ng-model="name"/>
          [ <a href="" ng-click="greet()">greet</a> ]<br/>
          Contact:
          <ul>
            <li ng-repeat="contact in contacts">
              <select ng-model="contact.type">
                 <option>phone</option>
                 <option>email</option>
              </select>
              <input type="text" ng-model="contact.value"/>
              [ <a href="" ng-click="clearContact(contact)">clear</a>
              | <a href="" ng-click="removeContact(contact)">X</a> ]
            </li>
            <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
         </ul>
        </div>
       </doc:source>
       <doc:scenario>
         it('should check controller', function() {
           expect(element('.doc-example-live div>:input').val()).toBe('John Smith');
           expect(element('.doc-example-live li:nth-child(1) input').val())
             .toBe('408 555 1212');
           expect(element('.doc-example-live li:nth-child(2) input').val())
             .toBe('john.smith@example.org');
  
           element('.doc-example-live li:first a:contains("clear")').click();
           expect(element('.doc-example-live li:first input').val()).toBe('');
  
           element('.doc-example-live li:last a:contains("add")').click();
           expect(element('.doc-example-live li:nth-child(3) input').val())
             .toBe('yourname@example.org');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngControllerDirective = [function() {
    return {
      scope: true,
      controller: '@'
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-click
   *
   * @description
   * The ng-click allows you to specify custom behavior when
   * element is clicked.
   *
   * @element ANY
   * @param {expression} ng-click {@link guide/dev_guide.expressions Expression} to evaluate upon
   * click. (Event object is available as `$event`)
   *
   * @example
     <doc:example>
       <doc:source>
        <button ng-click="count = count + 1" ng-init="count=0">
          Increment
        </button>
        count: {{count}}
       </doc:source>
       <doc:scenario>
         it('should check ng-click', function() {
           expect(binding('count')).toBe('0');
           element('.doc-example-live :button').click();
           expect(binding('count')).toBe('1');
         });
       </doc:scenario>
     </doc:example>
   */
  /*
   * A directive that allows creation of custom onclick handlers that are defined as angular
   * expressions and are compiled and executed within the current scope.
   *
   * Events that are handled via these handler are always configured not to propagate further.
   */
  var ngEventDirectives = {};
  forEach(
    'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
    function(name) {
      var directiveName = directiveNormalize('ng-' + name);
      ngEventDirectives[directiveName] = ['$parse', function($parse) {
        return function(scope, element, attr) {
          var fn = $parse(attr[directiveName]);
          element.bind(lowercase(name), function(event) {
            scope.$apply(function() {
              fn(scope, {$event:event});
            });
          });
        };
      }];
    }
  );
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-dblclick
   *
   * @description
   * The ng-dblclick allows you to specify custom behavior on dblclick event.
   *
   * @element ANY
   * @param {expression} ng-dblclick {@link guide/dev_guide.expressions Expression} to evaluate upon
   * dblclick. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mousedown
   *
   * @description
   * The ng-mousedown allows you to specify custom behavior on mousedown event.
   *
   * @element ANY
   * @param {expression} ng-mousedown {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mousedown. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mouseup
   *
   * @description
   * Specify custom behavior on mouseup event.
   *
   * @element ANY
   * @param {expression} ng-mouseup {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mouseup. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mouseover
   *
   * @description
   * Specify custom behavior on mouseover event.
   *
   * @element ANY
   * @param {expression} ng-mouseover {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mouseover. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mouseenter
   *
   * @description
   * Specify custom behavior on mouseenter event.
   *
   * @element ANY
   * @param {expression} ng-mouseenter {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mouseenter. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mouseleave
   *
   * @description
   * Specify custom behavior on mouseleave event.
   *
   * @element ANY
   * @param {expression} ng-mouseleave {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mouseleave. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-mousemove
   *
   * @description
   * Specify custom behavior on mousemove event.
   *
   * @element ANY
   * @param {expression} ng-mousemove {@link guide/dev_guide.expressions Expression} to evaluate upon
   * mousemove. (Event object is available as `$event`)
   *
   * @example
   * See {@link angular.module.ng.$compileProvider.directive.ng-click ng-click}
   */
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-submit
   *
   * @description
   * Enables binding angular expressions to onsubmit events.
   *
   * Additionally it prevents the default action (which for form means sending the request to the
   * server and reloading the current page).
   *
   * @element form
   * @param {expression} ng-submit {@link guide/dev_guide.expressions Expression} to eval.
   *
   * @example
     <doc:example>
       <doc:source>
        <script>
          function Ctrl($scope) {
            $scope.list = [];
            $scope.text = 'hello';
            $scope.submit = function() {
              if (this.text) {
                this.list.push(this.text);
                this.text = '';
              }
            };
          }
        </script>
        <form ng-submit="submit()" ng-controller="Ctrl">
          Enter text and hit enter:
          <input type="text" ng-model="text" name="text" />
          <input type="submit" id="submit" value="Submit" />
          <pre>list={{list}}</pre>
        </form>
       </doc:source>
       <doc:scenario>
         it('should check ng-submit', function() {
           expect(binding('list')).toBe('[]');
           element('.doc-example-live #submit').click();
           expect(binding('list')).toBe('["hello"]');
           expect(input('text').val()).toBe('');
         });
         it('should ignore empty strings', function() {
           expect(binding('list')).toBe('[]');
           element('.doc-example-live #submit').click();
           element('.doc-example-live #submit').click();
           expect(binding('list')).toBe('["hello"]');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
    element.bind('submit', function() {
      scope.$apply(attrs.ngSubmit);
    });
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-include
   * @restrict ECA
   *
   * @description
   * Fetches, compiles and includes an external HTML fragment.
   *
   * Keep in mind that Same Origin Policy applies to included resources
   * (e.g. ng-include won't work for file:// access).
   *
   * @scope
   *
   * @param {string} ng-include|src angular expression evaluating to URL. If the source is a string constant,
   *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
   * @param {string=} onload Expression to evaluate when a new partial is loaded.
   *
   * @param {string=} autoscroll Whether `ng-include` should call {@link angular.module.ng.$anchorScroll
   *                  $anchorScroll} to scroll the viewport after the content is loaded.
   *
   *                  - If the attribute is not set, disable scrolling.
   *                  - If the attribute is set without value, enable scrolling.
   *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
   *
   * @example
      <doc:example>
        <doc:source jsfiddle="false">
         <script>
           function Ctrl($scope) {
             $scope.templates =
               [ { name: 'template1.html', url: 'examples/ng-include/template1.html'}
               , { name: 'template2.html', url: 'examples/ng-include/template2.html'} ];
             $scope.template = $scope.templates[0];
           }
         </script>
         <div ng-controller="Ctrl">
           <select ng-model="template" ng-options="t.name for t in templates">
            <option value="">(blank)</option>
           </select>
           url of the template: <tt><a href="{{template.url}}">{{template.url}}</a></tt>
           <hr/>
           <div ng-include src="template.url"></div>
         </div>
        </doc:source>
        <doc:scenario>
          it('should load template1.html', function() {
           expect(element('.doc-example-live [ng-include]').text()).
             toBe('Content of template1.html\n');
          });
          it('should load template2.html', function() {
           select('template').option('1');
           expect(element('.doc-example-live [ng-include]').text()).
             toBe('Content of template2.html\n');
          });
          it('should change to blank', function() {
           select('template').option('');
           expect(element('.doc-example-live [ng-include]').text()).toEqual('');
          });
        </doc:scenario>
      </doc:example>
   */
  
  
  /**
   * @ngdoc event
   * @name angular.module.ng.$compileProvider.directive.ng-include#$includeContentLoaded
   * @eventOf angular.module.ng.$compileProvider.directive.ng-include
   * @eventType emit on the current ng-include scope
   * @description
   * Emitted every time the ng-include content is reloaded.
   */
  var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile',
                    function($http,   $templateCache,   $anchorScroll,   $compile) {
    return {
      restrict: 'ECA',
      terminal: true,
      compile: function(element, attr) {
        var srcExp = attr.ngInclude || attr.src,
            onloadExp = attr.onload || '',
            autoScrollExp = attr.autoscroll;
  
        return function(scope, element, attr) {
          var changeCounter = 0,
              childScope;
  
          var clearContent = function() {
            if (childScope) {
              childScope.$destroy();
              childScope = null;
            }
  
            element.html('');
          };
  
          scope.$watch(srcExp, function(src) {
            var thisChangeId = ++changeCounter;
  
            if (src) {
              $http.get(src, {cache: $templateCache}).success(function(response) {
                if (thisChangeId !== changeCounter) return;
  
                if (childScope) childScope.$destroy();
                childScope = scope.$new();
  
                element.html(response);
                $compile(element.contents())(childScope);
  
                if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
                  $anchorScroll();
                }
  
                childScope.$emit('$includeContentLoaded');
                scope.$eval(onloadExp);
              }).error(function() {
                if (thisChangeId === changeCounter) clearContent();
              });
            } else clearContent();
          });
        };
      }
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-init
   *
   * @description
   * The `ng-init` attribute specifies initialization tasks to be executed
   *  before the template enters execution mode during bootstrap.
   *
   * @element ANY
   * @param {expression} ng-init {@link guide/dev_guide.expressions Expression} to eval.
   *
   * @example
     <doc:example>
       <doc:source>
      <div ng-init="greeting='Hello'; person='World'">
        {{greeting}} {{person}}!
      </div>
       </doc:source>
       <doc:scenario>
         it('should check greeting', function() {
           expect(binding('greeting')).toBe('Hello');
           expect(binding('person')).toBe('World');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngInitDirective = ngDirective({
    compile: function() {
      return {
        pre: function(scope, element, attrs) {
          scope.$eval(attrs.ngInit);
        }
      }
    }
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-non-bindable
   * @priority 1000
   *
   * @description
   * Sometimes it is necessary to write code which looks like bindings but which should be left alone
   * by angular. Use `ng-non-bindable` to make angular ignore a chunk of HTML.
   *
   * @element ANY
   *
   * @example
   * In this example there are two location where a simple binding (`{{}}`) is present, but the one
   * wrapped in `ng-non-bindable` is left alone.
   *
   * @example
      <doc:example>
        <doc:source>
          <div>Normal: {{1 + 2}}</div>
          <div ng-non-bindable>Ignored: {{1 + 2}}</div>
        </doc:source>
        <doc:scenario>
         it('should check ng-non-bindable', function() {
           expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
           expect(using('.doc-example-live').element('div:last').text()).
             toMatch(/1 \+ 2/);
         });
        </doc:scenario>
      </doc:example>
   */
  var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-pluralize
   * @restrict EA
   *
   * @description
   * # Overview
   * ng-pluralize is a directive that displays messages according to en-US localization rules.
   * These rules are bundled with angular.js and the rules can be overridden
   * (see {@link guide/dev_guide.i18n Angular i18n} dev guide). You configure ng-pluralize by
   * specifying the mappings between
   * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
   * plural categories} and the strings to be displayed.
   *
   * # Plural categories and explicit number rules
   * There are two
   * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
   * plural categories} in Angular's default en-US locale: "one" and "other".
   *
   * While a pural category may match many numbers (for example, in en-US locale, "other" can match
   * any number that is not 1), an explicit number rule can only match one number. For example, the
   * explicit number rule for "3" matches the number 3. You will see the use of plural categories
   * and explicit number rules throughout later parts of this documentation.
   *
   * # Configuring ng-pluralize
   * You configure ng-pluralize by providing 2 attributes: `count` and `when`.
   * You can also provide an optional attribute, `offset`.
   *
   * The value of the `count` attribute can be either a string or an {@link guide/dev_guide.expressions
   * Angular expression}; these are evaluated on the current scope for its binded value.
   *
   * The `when` attribute specifies the mappings between plural categories and the actual
   * string to be displayed. The value of the attribute should be a JSON object so that Angular
   * can interpret it correctly.
   *
   * The following example shows how to configure ng-pluralize:
   *
   * <pre>
   * <ng-pluralize count="personCount"
                   when="{'0': 'Nobody is viewing.',
   *                      'one': '1 person is viewing.',
   *                      'other': '{} people are viewing.'}">
   * </ng-pluralize>
   *</pre>
   *
   * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
   * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
   * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
   * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
   * show "a dozen people are viewing".
   *
   * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
   * into pluralized strings. In the previous example, Angular will replace `{}` with
   * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
   * for <span ng-non-bindable>{{numberExpression}}</span>.
   *
   * # Configuring ng-pluralize with offset
   * The `offset` attribute allows further customization of pluralized text, which can result in
   * a better user experience. For example, instead of the message "4 people are viewing this document",
   * you might display "John, Kate and 2 others are viewing this document".
   * The offset attribute allows you to offset a number by any desired value.
   * Let's take a look at an example:
   *
   * <pre>
   * <ng-pluralize count="personCount" offset=2
   *               when="{'0': 'Nobody is viewing.',
   *                      '1': '{{person1}} is viewing.',
   *                      '2': '{{person1}} and {{person2}} are viewing.',
   *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
   *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
   * </ng-pluralize>
   * </pre>
   *
   * Notice that we are still using two plural categories(one, other), but we added
   * three explicit number rules 0, 1 and 2.
   * When one person, perhaps John, views the document, "John is viewing" will be shown.
   * When three people view the document, no explicit number rule is found, so
   * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
   * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
   * is shown.
   *
   * Note that when you specify offsets, you must provide explicit number rules for
   * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
   * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
   * plural categories "one" and "other".
   *
   * @param {string|expression} count The variable to be bounded to.
   * @param {string} when The mapping between plural category to its correspoding strings.
   * @param {number=} offset Offset to deduct from the total number.
   *
   * @example
      <doc:example>
        <doc:source>
          <script>
            function Ctrl($scope) {
              $scope.person1 = 'Igor';
              $scope.person2 = 'Misko';
              $scope.personCount = 1;
            }
          </script>
          <div ng-controller="Ctrl">
            Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
            Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
            Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
  
            <!--- Example with simple pluralization rules for en locale --->
            Without Offset:
            <ng-pluralize count="personCount"
                          when="{'0': 'Nobody is viewing.',
                                 'one': '1 person is viewing.',
                                 'other': '{} people are viewing.'}">
            </ng-pluralize><br>
  
            <!--- Example with offset --->
            With Offset(2):
            <ng-pluralize count="personCount" offset=2
                          when="{'0': 'Nobody is viewing.',
                                 '1': '{{person1}} is viewing.',
                                 '2': '{{person1}} and {{person2}} are viewing.',
                                 'one': '{{person1}}, {{person2}} and one other person are viewing.',
                                 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
            </ng-pluralize>
          </div>
        </doc:source>
        <doc:scenario>
          it('should show correct pluralized string', function() {
            expect(element('.doc-example-live ng-pluralize:first').text()).
                                               toBe('1 person is viewing.');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                                                  toBe('Igor is viewing.');
  
            using('.doc-example-live').input('personCount').enter('0');
            expect(element('.doc-example-live ng-pluralize:first').text()).
                                                 toBe('Nobody is viewing.');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                                                toBe('Nobody is viewing.');
  
            using('.doc-example-live').input('personCount').enter('2');
            expect(element('.doc-example-live ng-pluralize:first').text()).
                                              toBe('2 people are viewing.');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                                toBe('Igor and Misko are viewing.');
  
            using('.doc-example-live').input('personCount').enter('3');
            expect(element('.doc-example-live ng-pluralize:first').text()).
                                              toBe('3 people are viewing.');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                                toBe('Igor, Misko and one other person are viewing.');
  
            using('.doc-example-live').input('personCount').enter('4');
            expect(element('.doc-example-live ng-pluralize:first').text()).
                                              toBe('4 people are viewing.');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                                toBe('Igor, Misko and 2 other people are viewing.');
          });
  
          it('should show data-binded names', function() {
            using('.doc-example-live').input('personCount').enter('4');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                toBe('Igor, Misko and 2 other people are viewing.');
  
            using('.doc-example-live').input('person1').enter('Di');
            using('.doc-example-live').input('person2').enter('Vojta');
            expect(element('.doc-example-live ng-pluralize:last').text()).
                toBe('Di, Vojta and 2 other people are viewing.');
          });
        </doc:scenario>
      </doc:example>
   */
  var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
    var BRACE = /{}/g;
    return {
      restrict: 'EA',
      link: function(scope, element, attr) {
        var numberExp = attr.count,
            whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs
            offset = attr.offset || 0,
            whens = scope.$eval(whenExp),
            whensExpFns = {};
  
        forEach(whens, function(expression, key) {
          whensExpFns[key] =
            $interpolate(expression.replace(BRACE, '{{' + numberExp + '-' + offset + '}}'));
        });
  
        scope.$watch(function() {
          var value = parseFloat(scope.$eval(numberExp));
  
          if (!isNaN(value)) {
            //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
            //check it against pluralization rules in $locale service
            if (!whens[value]) value = $locale.pluralCat(value - offset);
             return whensExpFns[value](scope, element, true);
          } else {
            return '';
          }
        }, function(newVal) {
          element.text(newVal);
        });
      }
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-repeat
   *
   * @description
   * The `ng-repeat` 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:
   *
   *   * `$index` â€“ `{number}` â€“ iterator offset of the repeated element (0..length-1)
   *   * `$position` â€“ `{string}` â€“ position of the repeated element in the iterator. One of:
   *        * `'first'`,
   *        * `'middle'`
   *        * `'last'`
   *
   *
   * @element ANY
   * @scope
   * @priority 1000
   * @param {repeat_expression} ng-repeat The expression indicating how to enumerate a collection. Two
   *   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: `track in cd.tracks`.
   *
   *   * `(key, value) in expression` â€“ where `key` and `value` can be any user defined identifiers,
   *     and `expression` is the scope expression giving the collection to enumerate.
   *
   *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
   *
   * @example
   * This example initializes the scope to a list of names and
   * then uses `ng-repeat` to display every person:
      <doc:example>
        <doc:source>
          <div ng-init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]">
            I have {{friends.length}} friends. They are:
            <ul>
              <li ng-repeat="friend in friends">
                [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
              </li>
            </ul>
          </div>
        </doc:source>
        <doc:scenario>
           it('should check ng-repeat', function() {
             var r = using('.doc-example-live').repeater('ul li');
             expect(r.count()).toBe(2);
             expect(r.row(0)).toEqual(["1","John","25"]);
             expect(r.row(1)).toEqual(["2","Mary","28"]);
           });
        </doc:scenario>
      </doc:example>
   */
  var ngRepeatDirective = ngDirective({
    transclude: 'element',
    priority: 1000,
    terminal: true,
    compile: function(element, attr, linker) {
      return function(scope, iterStartElement, attr){
        var expression = attr.ngRepeat;
        var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
          lhs, rhs, valueIdent, keyIdent;
        if (! match) {
          throw Error("Expected ng-repeat in form of '_item_ in _collection_' but got '" +
            expression + "'.");
        }
        lhs = match[1];
        rhs = match[2];
        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
        if (!match) {
          throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
              lhs + "'.");
        }
        valueIdent = match[3] || match[1];
        keyIdent = match[2];
  
        // Store a list of elements from previous run. This is a hash where key is the item from the
        // iterator, and the value is an array of objects with following properties.
        //   - scope: bound scope
        //   - element: previous element.
        //   - index: position
        // We need an array of these objects since the same object can be returned from the iterator.
        // We expect this to be a rare case.
        var lastOrder = new HashQueueMap();
        scope.$watch(function(scope){
          var index, length,
              collection = scope.$eval(rhs),
              collectionLength = size(collection, true),
              childScope,
              // Same as lastOrder but it has the current state. It will become the
              // lastOrder on the next iteration.
              nextOrder = new HashQueueMap(),
              key, value, // key/value of iteration
              array, last,       // last object information {scope, element, index}
              cursor = iterStartElement;     // current position of the node
  
          if (!isArray(collection)) {
            // if object, extract keys, sort them and use to determine order of iteration over obj props
            array = [];
            for(key in collection) {
              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
                array.push(key);
              }
            }
            array.sort();
          } else {
            array = collection || [];
          }
  
          // we are not using forEach for perf reasons (trying to avoid #call)
          for (index = 0, length = array.length; index < length; index++) {
            key = (collection === array) ? index : array[index];
            value = collection[key];
            last = lastOrder.shift(value);
            if (last) {
              // if we have already seen this object, then we need to reuse the
              // associated scope/element
              childScope = last.scope;
              nextOrder.push(value, last);
  
              if (index === last.index) {
                // do nothing
                cursor = last.element;
              } else {
                // existing item which got moved
                last.index = index;
                // This may be a noop, if the element is next, but I don't know of a good way to
                // figure this out,  since it would require extra DOM access, so let's just hope that
                // the browsers realizes that it is noop, and treats it as such.
                cursor.after(last.element);
                cursor = last.element;
              }
            } else {
              // new item which we don't know about
              childScope = scope.$new();
            }
  
            childScope[valueIdent] = value;
            if (keyIdent) childScope[keyIdent] = key;
            childScope.$index = index;
            childScope.$position = index === 0 ?
                'first' :
                (index == collectionLength - 1 ? 'last' : 'middle');
  
            if (!last) {
              linker(childScope, function(clone){
                cursor.after(clone);
                last = {
                    scope: childScope,
                    element: (cursor = clone),
                    index: index
                  };
                nextOrder.push(value, last);
              });
            }
          }
  
          //shrink children
          for (key in lastOrder) {
            if (lastOrder.hasOwnProperty(key)) {
              array = lastOrder[key];
              while(array.length) {
                value = array.pop();
                value.element.remove();
                value.scope.$destroy();
              }
            }
          }
  
          lastOrder = nextOrder;
        });
      };
    }
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-show
   *
   * @description
   * The `ng-show` and `ng-hide` directives show or hide a portion of the DOM tree (HTML)
   * conditionally.
   *
   * @element ANY
   * @param {expression} ng-show If the {@link guide/dev_guide.expressions expression} is truthy
   *     then the element is shown or hidden respectively.
   *
   * @example
     <doc:example>
       <doc:source>
          Click me: <input type="checkbox" ng-model="checked"><br/>
          Show: <span ng-show="checked">I show up when your checkbox is checked.</span> <br/>
          Hide: <span ng-hide="checked">I hide when your checkbox is checked.</span>
       </doc:source>
       <doc:scenario>
         it('should check ng-show / ng-hide', function() {
           expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
           expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
  
           input('checked').check();
  
           expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
           expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
         });
       </doc:scenario>
     </doc:example>
   */
  //TODO(misko): refactor to remove element from the DOM
  var ngShowDirective = ngDirective(function(scope, element, attr){
    scope.$watch(attr.ngShow, function(value){
      element.css('display', toBoolean(value) ? '' : 'none');
    });
  });
  
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-hide
   *
   * @description
   * The `ng-hide` and `ng-show` directives hide or show a portion
   * of the HTML conditionally.
   *
   * @element ANY
   * @param {expression} ng-hide If the {@link guide/dev_guide.expressions expression} truthy then
   *     the element is shown or hidden respectively.
   *
   * @example
     <doc:example>
       <doc:source>
          Click me: <input type="checkbox" ng-model="checked"><br/>
          Show: <span ng-show="checked">I show up when you checkbox is checked?</span> <br/>
          Hide: <span ng-hide="checked">I hide when you checkbox is checked?</span>
       </doc:source>
       <doc:scenario>
         it('should check ng-show / ng-hide', function() {
           expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
           expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
  
           input('checked').check();
  
           expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
           expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
         });
       </doc:scenario>
     </doc:example>
   */
  //TODO(misko): refactor to remove element from the DOM
  var ngHideDirective = ngDirective(function(scope, element, attr){
    scope.$watch(attr.ngHide, function(value){
      element.css('display', toBoolean(value) ? 'none' : '');
    });
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-style
   *
   * @description
   * The ng-style allows you to set CSS style on an HTML element conditionally.
   *
   * @element ANY
   * @param {expression} ng-style {@link guide/dev_guide.expressions Expression} which evals to an
   *      object whose keys are CSS style names and values are corresponding values for those CSS
   *      keys.
   *
   * @example
     <doc:example>
       <doc:source>
          <input type="button" value="set" ng-click="myStyle={color:'red'}">
          <input type="button" value="clear" ng-click="myStyle={}">
          <br/>
          <span ng-style="myStyle">Sample Text</span>
          <pre>myStyle={{myStyle}}</pre>
       </doc:source>
       <doc:scenario>
         it('should check ng-style', function() {
           expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
           element('.doc-example-live :button[value=set]').click();
           expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
           element('.doc-example-live :button[value=clear]').click();
           expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
         });
       </doc:scenario>
     </doc:example>
   */
  var ngStyleDirective = ngDirective(function(scope, element, attr) {
    scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
      if (oldStyles && (newStyles !== oldStyles)) {
        forEach(oldStyles, function(val, style) { element.css(style, '');});
      }
      if (newStyles) element.css(newStyles);
    }, true);
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-switch
   * @restrict EA
   *
   * @description
   * Conditionally change the DOM structure.
   *
   * @usageContent
   * <any ng-switch-when="matchValue1">...</any>
   *   <any ng-switch-when="matchValue2">...</any>
   *   ...
   *   <any ng-switch-default>...</any>
   *
   * @scope
   * @param {*} ng-switch|on expression to match against <tt>ng-switch-when</tt>.
   * @paramDescription
   * On child elments add:
   *
   * * `ng-switch-when`: the case statement to match against. If match then this
   *   case will be displayed.
   * * `ng-switch-default`: the default case when no other casses match.
   *
   * @example
      <doc:example>
        <doc:source>
          <script>
            function Ctrl($scope) {
              $scope.items = ['settings', 'home', 'other'];
              $scope.selection = $scope.items[0];
            }
          </script>
          <div ng-controller="Ctrl">
            <select ng-model="selection" ng-options="item for item in items">
            </select>
            <tt>selection={{selection}}</tt>
            <hr/>
            <div ng-switch on="selection" >
              <div ng-switch-when="settings">Settings Div</div>
              <span ng-switch-when="home">Home Span</span>
              <span ng-switch-default>default</span>
            </div>
          </div>
        </doc:source>
        <doc:scenario>
          it('should start in settings', function() {
           expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
          });
          it('should change to home', function() {
           select('selection').option('home');
           expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
          });
          it('should select deafault', function() {
           select('selection').option('other');
           expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
          });
        </doc:scenario>
      </doc:example>
   */
  var NG_SWITCH = 'ng-switch';
  var ngSwitchDirective = valueFn({
    restrict: 'EA',
    compile: function(element, attr) {
      var watchExpr = attr.ngSwitch || attr.on,
          cases = {};
  
      element.data(NG_SWITCH, cases);
      return function(scope, element){
        var selectedTransclude,
            selectedElement,
            selectedScope;
  
        scope.$watch(watchExpr, function(value) {
          if (selectedElement) {
            selectedScope.$destroy();
            selectedElement.remove();
            selectedElement = selectedScope = null;
          }
          if ((selectedTransclude = cases['!' + value] || cases['?'])) {
            scope.$eval(attr.change);
            selectedScope = scope.$new();
            selectedTransclude(selectedScope, function(caseElement) {
              selectedElement = caseElement;
              element.append(caseElement);
            });
          }
        });
      };
    }
  });
  
  var ngSwitchWhenDirective = ngDirective({
    transclude: 'element',
    priority: 500,
    compile: function(element, attrs, transclude) {
      var cases = element.inheritedData(NG_SWITCH);
      assertArg(cases);
      cases['!' + attrs.ngSwitchWhen] = transclude;
    }
  });
  
  var ngSwitchDefaultDirective = ngDirective({
    transclude: 'element',
    priority: 500,
    compile: function(element, attrs, transclude) {
      var cases = element.inheritedData(NG_SWITCH);
      assertArg(cases);
      cases['?'] = transclude;
    }
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-transclude
   *
   * @description
   * Insert the transcluded DOM here.
   *
   * @element ANY
   *
   * @example
     <doc:example module="transclude">
       <doc:source>
         <script>
           function Ctrl($scope) {
             $scope.title = 'Lorem Ipsum';
             $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
           }
  
           angular.module('transclude', [])
            .directive('pane', function(){
               return {
                 restrict: 'E',
                 transclude: true,
                 scope: 'isolate',
                 locals: { title:'bind' },
                 template: '<div style="border: 1px solid black;">' +
                             '<div style="background-color: gray">{{title}}</div>' +
                             '<div ng-transclude></div>' +
                           '</div>'
               };
           });
         </script>
         <div ng-controller="Ctrl">
           <input ng-model="title"><br>
           <textarea ng-model="text"></textarea> <br/>
           <pane title="{{title}}">{{text}}</pane>
         </div>
       </doc:source>
       <doc:scenario>
          it('should have transcluded', function() {
            input('title').enter('TITLE');
            input('text').enter('TEXT');
            expect(binding('title')).toEqual('TITLE');
            expect(binding('text')).toEqual('TEXT');
          });
       </doc:scenario>
     </doc:example>
   *
   */
  var ngTranscludeDirective = ngDirective({
    controller: ['$transclude', '$element', function($transclude, $element) {
      $transclude(function(clone) {
        $element.append(clone);
      });
    }]
  });
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.ng-view
   * @restrict ECA
   *
   * @description
   * # Overview
   * `ng-view` is a directive that complements the {@link angular.module.ng.$route $route} service by
   * including the rendered template of the current route into the main layout (`index.html`) file.
   * Every time the current route changes, the included view changes with it according to the
   * configuration of the `$route` service.
   *
   * @scope
   * @example
      <doc:example module="ngView">
        <doc:source>
          <script type="text/ng-template" id="examples/book.html">
            controller: {{name}}<br />
            Book Id: {{params.bookId}}<br />
          </script>
  
          <script type="text/ng-template" id="examples/chapter.html">
            controller: {{name}}<br />
            Book Id: {{params.bookId}}<br />
            Chapter Id: {{params.chapterId}}
          </script>
  
          <script>
            angular.module('ngView', [], function($routeProvider, $locationProvider) {
              $routeProvider.when('/Book/:bookId', {
                template: 'examples/book.html',
                controller: BookCntl
              });
              $routeProvider.when('/Book/:bookId/ch/:chapterId', {
                template: 'examples/chapter.html',
                controller: ChapterCntl
              });
  
              // configure html5 to get links working on jsfiddle
              $locationProvider.html5Mode(true);
            });
  
            function MainCntl($scope, $route, $routeParams, $location) {
              $scope.$route = $route;
              $scope.$location = $location;
              $scope.$routeParams = $routeParams;
            }
  
            function BookCntl($scope, $routeParams) {
              $scope.name = "BookCntl";
              $scope.params = $routeParams;
            }
  
            function ChapterCntl($scope, $routeParams) {
              $scope.name = "ChapterCntl";
              $scope.params = $routeParams;
            }
          </script>
  
          <div ng-controller="MainCntl">
            Choose:
            <a href="/Book/Moby">Moby</a> |
            <a href="/Book/Moby/ch/1">Moby: Ch1</a> |
            <a href="/Book/Gatsby">Gatsby</a> |
            <a href="/Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
            <a href="/Book/Scarlet">Scarlet Letter</a><br/>
  
            <div ng-view></div>
            <hr />
  
            <pre>$location.path() = {{$location.path()}}</pre>
            <pre>$route.current.template = {{$route.current.template}}</pre>
            <pre>$route.current.params = {{$route.current.params}}</pre>
            <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
            <pre>$routeParams = {{$routeParams}}</pre>
          </div>
        </doc:source>
        <doc:scenario>
          it('should load and compile correct template', function() {
            element('a:contains("Moby: Ch1")').click();
            var content = element('.doc-example-live [ng-view]').text();
            expect(content).toMatch(/controller\: ChapterCntl/);
            expect(content).toMatch(/Book Id\: Moby/);
            expect(content).toMatch(/Chapter Id\: 1/);
  
            element('a:contains("Scarlet")').click();
            content = element('.doc-example-live [ng-view]').text();
            expect(content).toMatch(/controller\: BookCntl/);
            expect(content).toMatch(/Book Id\: Scarlet/);
          });
        </doc:scenario>
      </doc:example>
   */
  
  
  /**
   * @ngdoc event
   * @name angular.module.ng.$compileProvider.directive.ng-view#$viewContentLoaded
   * @eventOf angular.module.ng.$compileProvider.directive.ng-view
   * @eventType emit on the current ng-view scope
   * @description
   * Emitted every time the ng-view content is reloaded.
   */
  var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$compile',
                         '$controller',
                 function($http,   $templateCache,   $route,   $anchorScroll,   $compile,
                          $controller) {
    return {
      restrict: 'ECA',
      terminal: true,
      link: function(scope, element, attr) {
        var changeCounter = 0,
            lastScope,
            onloadExp = attr.onload || '';
  
        scope.$on('$afterRouteChange', update);
        update();
  
  
        function destroyLastScope() {
          if (lastScope) {
            lastScope.$destroy();
            lastScope = null;
          }
        }
  
        function update() {
          var template = $route.current && $route.current.template,
              thisChangeId = ++changeCounter;
  
          function clearContent() {
            // ignore callback if another route change occured since
            if (thisChangeId === changeCounter) {
              element.html('');
              destroyLastScope();
            }
          }
  
          if (template) {
            $http.get(template, {cache: $templateCache}).success(function(response) {
              // ignore callback if another route change occured since
              if (thisChangeId === changeCounter) {
                element.html(response);
                destroyLastScope();
  
                var link = $compile(element.contents()),
                    current = $route.current,
                    controller;
  
                lastScope = current.scope = scope.$new();
                if (current.controller) {
                  controller = $controller(current.controller, {$scope: lastScope});
                  element.contents().data('$ngControllerController', controller);
                }
  
                link(lastScope);
                lastScope.$emit('$viewContentLoaded');
                lastScope.$eval(onloadExp);
  
                // $anchorScroll might listen on event...
                $anchorScroll();
              }
            }).error(clearContent);
          } else {
            clearContent();
          }
        }
      }
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.script
   *
   * @description
   * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
   * template can be used by `ng-include`, `ng-view` or directive templates.
   *
   * @restrict E
   * @param {'text/ng-template'} type must be set to `'text/ng-template'`
   *
   * @example
    <doc:example>
      <doc:source>
        <script type="text/ng-template" id="/tpl.html">
          Content of the template.
        </script>
  
        <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
        <div id="tpl-content" ng-include src="currentTpl"></div>
      </doc:source>
      <doc:scenario>
        it('should load template defined inside script tag', function() {
          element('#tpl-link').click();
          expect(element('#tpl-content').text()).toMatch(/Content of the template/);
        });
      </doc:scenario>
    </doc:example>
   */
  var scriptDirective = ['$templateCache', function($templateCache) {
    return {
      restrict: 'E',
      terminal: true,
      compile: function(element, attr) {
        if (attr.type == 'text/ng-template') {
          var templateUrl = attr.id;
          $templateCache.put(templateUrl, element.text());
        }
      }
    };
  }];
  
  /**
   * @ngdoc directive
   * @name angular.module.ng.$compileProvider.directive.select
   * @restrict E
   *
   * @description
   * HTML `SELECT` element with angular data-binding.
   *
   * # `ng-options`
   *
   * Optionally `ng-options` attribute can be used to dynamically generate a list of `<option>`
   * elements for a `<select>` element using an array or an object obtained by evaluating the
   * `ng-options` expression.
   *ËË
   * When an item in the select menu is select, the value of array element or object property
   * represented by the selected option will be bound to the model identified by the `ng-model` attribute
   * of the parent select element.
   *
   * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
   * be nested into the `<select>` element. This element will then represent `null` or "not selected"
   * option. See example below for demonstration.
   *
   * Note: `ng-options` provides iterator facility for `<option>` element which must be used instead
   * of {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat}. `ng-repeat` is not suitable for use with
   * `<option>` element because of the following reasons:
   *
   *   * value attribute of the option element that we need to bind to requires a string, but the
   *     source of data for the iteration might be in a form of array containing objects instead of
   *     strings
   *   * {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat} unrolls after the select binds causing
   *     incorect rendering on most browsers.
   *   * binding to a value not in list confuses most browsers.
   *
   * @param {string} name assignable expression to data-bind to.
   * @param {string=} required The control is considered valid only if value is entered.
   * @param {comprehension_expression=} ng-options in one of the following forms:
   *
   *   * for array data sources:
   *     * `label` **`for`** `value` **`in`** `array`
   *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
   *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
   *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
   *   * for object data sources:
   *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
   *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
   *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
   *     * `select` **`as`** `label` **`group by`** `group`
   *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
   *
   * Where:
   *
   *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
   *   * `value`: local variable which will refer to each item in the `array` or each property value
   *      of `object` during iteration.
   *   * `key`: local variable which will refer to a property name in `object` during iteration.
   *   * `label`: The result of this expression will be the label for `<option>` element. The
   *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
   *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
   *      element. If not specified, `select` expression will default to `value`.
   *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
   *      DOM element.
   *
   * @example
      <doc:example>
        <doc:source>
          <script>
          function MyCntrl($scope) {
            $scope.colors = [
              {name:'black', shade:'dark'},
              {name:'white', shade:'light'},
              {name:'red', shade:'dark'},
              {name:'blue', shade:'dark'},
              {name:'yellow', shade:'light'}
            ];
            $scope.color = $scope.colors[2]; // red
          }
          </script>
          <div ng-controller="MyCntrl">
            <ul>
              <li ng-repeat="color in colors">
                Name: <input ng-model="color.name">
                [<a href ng-click="colors.$remove(color)">X</a>]
              </li>
              <li>
                [<a href ng-click="colors.push({})">add</a>]
              </li>
            </ul>
            <hr/>
            Color (null not allowed):
            <select ng-model="color" ng-options="c.name for c in colors"></select><br>
  
            Color (null allowed):
            <div  class="nullable">
              <select ng-model="color" ng-options="c.name for c in colors">
                <option value="">-- chose color --</option>
              </select>
            </div><br/>
  
            Color grouped by shade:
            <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
            </select><br/>
  
  
            Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
            <hr/>
            Currently selected: {{ {selected_color:color}  }}
            <div style="border:solid 1px black; height:20px"
                 ng-style="{'background-color':color.name}">
            </div>
          </div>
        </doc:source>
        <doc:scenario>
           it('should check ng-options', function() {
             expect(binding('{selected_color:color}')).toMatch('red');
             select('color').option('0');
             expect(binding('{selected_color:color}')).toMatch('black');
             using('.nullable').select('color').option('');
             expect(binding('{selected_color:color}')).toMatch('null');
           });
        </doc:scenario>
      </doc:example>
   */
  
  var ngOptionsDirective = valueFn({ terminal: true });
  var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
                           //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777
    var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/;
  
    return {
      restrict: 'E',
      require: '?ngModel',
      link: function(scope, element, attr, ctrl) {
        if (!ctrl) return;
  
        var multiple = attr.multiple,
            optionsExp = attr.ngOptions;
  
        // required validator
        if (multiple && (attr.required || attr.ngRequired)) {
          var requiredValidator = function(value) {
            ctrl.$setValidity('required', !attr.required || (value && value.length));
            return value;
          };
  
          ctrl.$parsers.push(requiredValidator);
          ctrl.$formatters.unshift(requiredValidator);
  
          attr.$observe('required', function() {
            requiredValidator(ctrl.$viewValue);
          });
        }
  
        if (optionsExp) Options(scope, element, ctrl);
        else if (multiple) Multiple(scope, element, ctrl);
        else Single(scope, element, ctrl);
  
  
        ////////////////////////////
  
  
  
        function Single(scope, selectElement, ctrl) {
          ctrl.$render = function() {
            selectElement.val(ctrl.$viewValue);
          };
  
          selectElement.bind('change', function() {
            scope.$apply(function() {
              ctrl.$setViewValue(selectElement.val());
            });
          });
        }
  
        function Multiple(scope, selectElement, ctrl) {
          var lastView;
          ctrl.$render = function() {
            var items = new HashMap(ctrl.$viewValue);
            forEach(selectElement.children(), function(option) {
              option.selected = isDefined(items.get(option.value));
            });
          };
  
          // we have to do it on each watch since ng-model watches reference, but
          // we need to work of an array, so we need to see if anything was inserted/removed
          scope.$watch(function() {
            if (!equals(lastView, ctrl.$viewValue)) {
              lastView = copy(ctrl.$viewValue);
              ctrl.$render();
            }
          });
  
          selectElement.bind('change', function() {
            scope.$apply(function() {
              var array = [];
              forEach(selectElement.children(), function(option) {
                if (option.selected) {
                  array.push(option.value);
                }
              });
              ctrl.$setViewValue(array);
            });
          });
        }
  
        function Options(scope, selectElement, ctrl) {
          var match;
  
          if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
            throw Error(
              "Expected ng-options in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
              " but got '" + optionsExp + "'.");
          }
  
          var displayFn = $parse(match[2] || match[1]),
              valueName = match[4] || match[6],
              keyName = match[5],
              groupByFn = $parse(match[3] || ''),
              valueFn = $parse(match[2] ? match[1] : valueName),
              valuesFn = $parse(match[7]),
              // we can't just jqLite('<option>') since jqLite is not smart enough
              // to create it in <select> and IE barfs otherwise.
              optionTemplate = jqLite(document.createElement('option')),
              optGroupTemplate = jqLite(document.createElement('optgroup')),
              nullOption = false, // if false then user will not be able to select it
              // This is an array of array of existing option groups in DOM. We try to reuse these if possible
              // optionGroupsCache[0] is the options with no option group
              // optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
              optionGroupsCache = [[{element: selectElement, label:''}]];
  
          // find existing special options
          forEach(selectElement.children(), function(option) {
            if (option.value == '') {
              // developer declared null option, so user should be able to select it
              nullOption = jqLite(option).remove();
              // compile the element since there might be bindings in it
              $compile(nullOption)(scope);
            }
          });
          selectElement.html(''); // clear contents
  
          selectElement.bind('change', function() {
            scope.$apply(function() {
              var optionGroup,
                  collection = valuesFn(scope) || [],
                  locals = {},
                  key, value, optionElement, index, groupIndex, length, groupLength;
  
              if (multiple) {
                value = [];
                for (groupIndex = 0, groupLength = optionGroupsCache.length;
                groupIndex < groupLength;
                groupIndex++) {
                  // list of options for that group. (first item has the parent)
                  optionGroup = optionGroupsCache[groupIndex];
  
                  for(index = 1, length = optionGroup.length; index < length; index++) {
                    if ((optionElement = optionGroup[index].element)[0].selected) {
                      key = optionElement.val();
                      if (keyName) locals[keyName] = key;
                      locals[valueName] = collection[key];
                      value.push(valueFn(scope, locals));
                    }
                  }
                }
              } else {
                key = selectElement.val();
                if (key == '?') {
                  value = undefined;
                } else if (key == ''){
                  value = null;
                } else {
                  locals[valueName] = collection[key];
                  if (keyName) locals[keyName] = key;
                  value = valueFn(scope, locals);
                }
              }
              ctrl.$setViewValue(value);
            });
          });
  
          ctrl.$render = render;
  
          // TODO(vojta): can't we optimize this ?
          scope.$watch(render);
  
          function render() {
            var optionGroups = {'':[]}, // Temporary location for the option groups before we render them
                optionGroupNames = [''],
                optionGroupName,
                optionGroup,
                option,
                existingParent, existingOptions, existingOption,
                modelValue = ctrl.$modelValue,
                values = valuesFn(scope) || [],
                keys = keyName ? sortedKeys(values) : values,
                groupLength, length,
                groupIndex, index,
                locals = {},
                selected,
                selectedSet = false, // nothing is selected yet
                lastElement,
                element;
  
            if (multiple) {
              selectedSet = new HashMap(modelValue);
            } else if (modelValue === null || nullOption) {
              // if we are not multiselect, and we are null then we have to add the nullOption
              optionGroups[''].push({selected:modelValue === null, id:'', label:''});
              selectedSet = true;
            }
  
            // We now build up the list of options we need (we merge later)
            for (index = 0; length = keys.length, index < length; index++) {
                 locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index];
                 optionGroupName = groupByFn(scope, locals) || '';
              if (!(optionGroup = optionGroups[optionGroupName])) {
                optionGroup = optionGroups[optionGroupName] = [];
                optionGroupNames.push(optionGroupName);
              }
              if (multiple) {
                selected = selectedSet.remove(valueFn(scope, locals)) != undefined;
              } else {
                selected = modelValue === valueFn(scope, locals);
                selectedSet = selectedSet || selected; // see if at least one item is selected
              }
              optionGroup.push({
                id: keyName ? keys[index] : index,   // either the index into array or key from object
                label: displayFn(scope, locals) || '', // what will be seen by the user
                selected: selected                   // determine if we should be selected
              });
            }
            if (!multiple && !selectedSet) {
              // nothing was selected, we have to insert the undefined item
              optionGroups[''].unshift({id:'?', label:'', selected:true});
            }
  
            // Now we need to update the list of DOM nodes to match the optionGroups we computed above
            for (groupIndex = 0, groupLength = optionGroupNames.length;
                 groupIndex < groupLength;
                 groupIndex++) {
              // current option group name or '' if no group
              optionGroupName = optionGroupNames[groupIndex];
  
              // list of options for that group. (first item has the parent)
              optionGroup = optionGroups[optionGroupName];
  
              if (optionGroupsCache.length <= groupIndex) {
                // we need to grow the optionGroups
                existingParent = {
                  element: optGroupTemplate.clone().attr('label', optionGroupName),
                  label: optionGroup.label
                };
                existingOptions = [existingParent];
                optionGroupsCache.push(existingOptions);
                selectElement.append(existingParent.element);
              } else {
                existingOptions = optionGroupsCache[groupIndex];
                existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
  
                // update the OPTGROUP label if not the same.
                if (existingParent.label != optionGroupName) {
                  existingParent.element.attr('label', existingParent.label = optionGroupName);
                }
              }
  
              lastElement = null;  // start at the begining
              for(index = 0, length = optionGroup.length; index < length; index++) {
                option = optionGroup[index];
                if ((existingOption = existingOptions[index+1])) {
                  // reuse elements
                  lastElement = existingOption.element;
                  if (existingOption.label !== option.label) {
                    lastElement.text(existingOption.label = option.label);
                  }
                  if (existingOption.id !== option.id) {
                    lastElement.val(existingOption.id = option.id);
                  }
                  if (existingOption.element.selected !== option.selected) {
                    lastElement.prop('selected', (existingOption.selected = option.selected));
                  }
                } else {
                  // grow elements
  
                  // if it's a null option
                  if (option.id === '' && nullOption) {
                    // put back the pre-compiled element
                    element = nullOption;
                  } else {
                    // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
                    // in this version of jQuery on some browser the .text() returns a string
                    // rather then the element.
                    (element = optionTemplate.clone())
                        .val(option.id)
                        .attr('selected', option.selected)
                        .text(option.label);
                  }
  
                  existingOptions.push(existingOption = {
                      element: element,
                      label: option.label,
                      id: option.id,
                      selected: option.selected
                  });
                  if (lastElement) {
                    lastElement.after(element);
                  } else {
                    existingParent.element.append(element);
                  }
                  lastElement = element;
                }
              }
              // remove any excessive OPTIONs in a group
              index++; // increment since the existingOptions[0] is parent element not OPTION
              while(existingOptions.length > index) {
                existingOptions.pop().element.remove();
              }
            }
            // remove any excessive OPTGROUPs from select
            while(optionGroupsCache.length > groupIndex) {
              optionGroupsCache.pop()[0].element.remove();
            }
          };
        }
      }
    }
  }];
  
  var optionDirective = ['$interpolate', function($interpolate) {
    return {
      restrict: 'E',
      priority: 100,
      compile: function(element, attr) {
        if (isUndefined(attr.value)) {
          var interpolateFn = $interpolate(element.text(), true);
          if (interpolateFn) {
            return function (scope, element, attr) {
              scope.$watch(interpolateFn, function(value) {
                attr.$set('value', value);
              });
            }
          } else {
            attr.$set('value', element.text());
          }
        }
      }
    }
  }];
  
  var styleDirective = valueFn({
    restrict: 'E',
    terminal: true
  });
    //try to bind to jquery now so that one can write angular.element().read()
    //but we will rebind on bootstrap again.
    bindJQuery();
  
    publishExternalAPI(angular);
  
    jqLite(document).ready(function() {
      angularInit(document, bootstrap);
    });
  
  })(window, document);
  angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');