Team:SYSU-CHINA/lib/angular/angularjs

/**

* @license AngularJS v1.0.3
* (c) 2010-2012 Google, Inc. http://angularjs.org
* License: MIT
*/

(function(window, document, undefined) { 'use strict';

////////////////////////////////////

/**

* @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 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,
   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`.
*
     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']);
   
*
* @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.
     function foo(callback) {
       var result = calculateResult();
       (callback || angular.noop)(result);
     }
   
*/

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.
*
     function transformer(transformationFn, value) {
       return (transformationFn || identity)(value);
     };
   
*/

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 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;

}


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 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 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 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('
').append(element).html().
     match(/^(<[^>]+>)/)[1].
     replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });

}


/////////////////////////////////////////////////

/**

* 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 method 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 ng.directive:ngApp
*
* @element ANY
* @param {angular.Module} ngApp an 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 `ngApp` directive would not be placed
* on the `html` element then the document would not be compiled
* and the `Template:1+2` would not be resolved to `3`.
*
* `ngApp` is the easiest way to bootstrap an application.
*
<doc:example>
  <doc:source>
   I can add: 1 + 2 =  Template: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/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}
* @returns {AUTO.$injector} Returns the newly created injector for this app.
*/

function bootstrap(element, modules) {

 element = jqLite(element);
 modules = modules || [];
 modules.unshift(['$provide', function($provide) {
   $provide.value('$rootElement', element);
 }]);
 modules.unshift('ng');
 var injector = createInjector(modules);
 injector.invoke(
   ['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, 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) {
   throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
 }
 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 configuration information. Module
    * is used to configure the {@link AUTO.$injector $injector}.
    *
*
     * // 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('!');
     * });
     * 
    *
    * Then you can create an injector and load your modules like this:
    *
*
     * var injector = angular.injector(['ng', 'MyModule'])
     * 
    *
    * However it's more likely that you'll just use
    * {@link ng.directive:ngApp ngApp} 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 Optional 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 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 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 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 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 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 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 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 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 should be performed when the injector is done
          * loading all modules.
          */
         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.3',    // all of these placeholder strings will be replaced by rake's
 major: 1,    // compile task
 minor: 0,
 dot: 3,
 codeName: 'bouncy-thunder'

};


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,
           ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
           ngBindTemplate: ngBindTemplateDirective,
           ngClass: ngClassDirective,
           ngClassEven: ngClassEvenDirective,
           ngClassOdd: ngClassOddDirective,
           ngCsp: ngCspDirective,
           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,
       $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,
       $sniffer: $SnifferProvider,
       $templateCache: $TemplateCacheProvider,
       $timeout: $TimeoutProvider,
       $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/)
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
* - [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 `ngController` 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/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 = JQLite.cache = {},

   jqName = JQLite.expando = '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; }


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, events;
   while(list.length) {
     set = list.shift();
     for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
       element = jqLite(set[setIndex]);
       if (fireEvent) {
         element.triggerHandler('$destroy');
       } 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 = '
 
' + 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 JQLiteUnbind(element, type, fn) {

 var events = JQLiteExpandoStore(element, 'events'),
     handle = JQLiteExpandoStore(element, 'handle');
 if (!handle) return; //no listeners registered
 if (isUndefined(type)) {
   forEach(events, function(eventHandler, type) {
     removeEventListenerFn(element, type, eventHandler);
     delete events[type];
   });
 } else {
   if (isUndefined(fn)) {
     removeEventListenerFn(element, type, events[type]);
     delete events[type];
   } else {
     arrayRemove(events[type], fn);
   }
 }

}

function JQLiteRemoveData(element) {

 var expandoId = element[jqName],
     expandoStore = jqCache[expandoId];
 if (expandoStore) {
   if (expandoStore.handle) {
     expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
     JQLiteUnbind(element);
   }
   delete jqCache[expandoId];
   element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
 }

}

function JQLiteExpandoStore(element, key, value) {

 var expandoId = element[jqName],
     expandoStore = jqCache[expandoId || -1];
 if (isDefined(value)) {
   if (!expandoStore) {
     element[jqName] = expandoId = jqNextId();
     expandoStore = jqCache[expandoId] = {};
   }
   expandoStore[key] = value;
 } else {
   return expandoStore && expandoStore[key];
 }

}

function JQLiteData(element, key, value) {

 var data = JQLiteExpandoStore(element, 'data'),
     isSetter = isDefined(value),
     keyDefined = !isSetter && isDefined(key),
     isSimpleGetter = keyDefined && !isObject(key);
 if (!data && !isSimpleGetter) {
   JQLiteExpandoStore(element, 'data', data = {});
 }
 if (isSetter) {
   data[key] = value;
 } else {
   if (keyDefined) {
     if (isSimpleGetter) {
       // don't create data in this case.
       return data && data[key];
     } else {
       extend(data, key);
     }
   } else {
     return data;
   }
 }

}

function JQLiteHasClass(element, selector) {

 return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
     indexOf( " " + selector + " " ) > -1);

}

function JQLiteRemoveClass(element, cssClasses) {

 if (cssClasses) {
   forEach(cssClasses.split(' '), function(cssClass) {
     element.className = trim(
         (" " + element.className + " ")
         .replace(/[\n\t]/g, " ")
         .replace(" " + trim(cssClass) + " ", " ")
     );
   });
 }

}

function JQLiteAddClass(element, cssClasses) {

 if (cssClasses) {
   forEach(cssClasses.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 getBooleanAttrName(element, name) {

 // check dom last since we will most likely fail on name
 var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
 // booleanAttr is here twice to minimize DOM access
 return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;

}

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++) {
         if (fn === JQLiteData) {
           // data() takes the whole object in jQuery
           fn(this[i], arg1);
         } else {
           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, events) {

 var eventHandler = function (event, type) {
   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(events[type || event.type], function(fn) {
     fn.call(element, event);
   });
   // Remove monkey-patched methods (IE),
   // as they would cause memory leaks in IE8.
   if (msie <= 8) {
     // IE7/8 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.elem = element;
 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 events = JQLiteExpandoStore(element, 'events'),
       handle = JQLiteExpandoStore(element, 'handle');
   if (!events) JQLiteExpandoStore(element, 'events', events = {});
   if (!handle) JQLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
   forEach(type.split(' '), function(type){
     var eventFns = events[type];
     if (!eventFns) {
       if (type == 'mouseenter' || type == 'mouseleave') {
         var counter = 0;
         events.mouseenter = [];
         events.mouseleave = [];
         bindFn(element, 'mouseover', function(event) {
           counter++;
           if (counter == 1) {
             handle(event, 'mouseenter');
           }
         });
         bindFn(element, 'mouseout', function(event) {
           counter --;
           if (counter == 0) {
             handle(event, 'mouseleave');
           }
         });
       } else {
         addEventListenerFn(element, type, handle);
         events[type] = [];
       }
       eventFns = events[type]
     }
     eventFns.push(fn);
   });
 },
 unbind: JQLiteUnbind,
 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,
 triggerHandler: function(element, eventName) {
   var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
   forEach(eventFns, function(fn) {
     fn.call(element, null);
   });
 }

}, 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();
     }
   }
 },
 /**
  * return the first item without deleting it
  */
 peek: function(key) {
   var array = this[hashKey(key)];
   if (array) {
   return array[0];
   }
 }

};

/**

* @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/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 AUTO.$injector $injector}.
*
* @example
* Typical usage
*
 *   // create an injector
 *   var $injector = angular.injector(['ng']);
 *
 *   // use the injector to kick off 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();
 *   });
 * 
*/


/**

* @ngdoc overview
* @name AUTO
* @description
*
* Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
*/

var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; function annotate(fn) {

 var $inject,
     fnText,
     argDecl,
     last;
 if (typeof fn == 'function') {
   if (!($inject = fn.$inject)) {
     $inject = [];
     fnText = fn.toString().replace(STRIP_COMMENTS, );
     argDecl = fnText.match(FN_ARGS);
     forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
       arg.replace(FN_ARG, function(all, underscore, name){
         $inject.push(name);
       });
     });
     fn.$inject = $inject;
   }
 } else if (isArray(fn)) {
   last = fn.length - 1;
   assertArgFn(fn[last], 'fn')
   $inject = fn.slice(0, last);
 } else {
   assertArgFn(fn, 'fn', true);
 }
 return $inject;

}

///////////////////////////////////////

/**

* @ngdoc object
* @name AUTO.$injector
* @function
*
* @description
*
* `$injector` is used to retrieve object instances as defined by
* {@link AUTO.$provide provider}, instantiate types, invoke methods,
* and load modules.
*
* The following always holds true:
*
*
 *   var $injector = angular.injector();
 *   expect($injector.get('$injector')).toBe($injector);
 *   expect($injector.invoke(function($injector){
 *     return $injector;
 *   }).toBe($injector);
 * 
*
* # 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.
*
*
 *   // 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){}]);
 * 
*
* ## 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 minification, 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 AUTO.$injector#get
* @methodOf 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 AUTO.$injector#invoke
* @methodOf 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.
* @returns {*} the value returned by the invoked `fn` function.
*/

/**

* @ngdoc method
* @name AUTO.$injector#instantiate
* @methodOf 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.
* @returns {Object} new instance of `Type`.
*/

/**

* @ngdoc method
* @name AUTO.$injector#annotate
* @methodOf AUTO.$injector
*
* @description
* Returns an array of service names which the function is requesting for injection. This API is used by the injector
* to determine which services need to be injected into the function when the function is invoked. There are three
* ways in which the function can be annotated with the needed dependencies.
*
* # Argument names
*
* The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
* the function into a string using `toString()` method and extracting the argument names.
*
 *   // Given
 *   function MyController($scope, $route) {
 *     // ...
 *   }
 *
 *   // Then
 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
 * 
*
* This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
* are supported.
*
* # The `$injector` property
*
* If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
* services to be injected into the function.
*
 *   // Given
 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
 *     // ...
 *   }
 *   // Define function dependencies
 *   MyController.$inject = ['$scope', '$route'];
 *
 *   // Then
 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
 * 
*
* # The array notation
*
* It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
* inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
* minification is a better choice:
*
*
 *   // We wish to write this (not minification / obfuscation safe)
 *   injector.invoke(function($compile, $rootScope) {
 *     // ...
 *   });
 *
 *   // We are forced to write break inlining
 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
 *     // ...
 *   };
 *   tmpFn.$inject = ['$compile', '$rootScope'];
 *   injector.invoke(tempFn);
 *
 *   // To better support inline function the inline annotation is supported
 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
 *     // ...
 *   }]);
 *
 *   // Therefore
 *   expect(injector.annotate(
 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
 *    ).toEqual(['$compile', '$rootScope']);
 * 
*
* @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
*   above.
*
* @returns {Array.<string>} The names of the services which the function requires.
*/



/**

* @ngdoc object
* @name 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.
*
*
 *   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!');
 *       });
 *     )};
 *
 *   });
 * 
*/

/**

* @ngdoc method
* @name AUTO.$provide#provider
* @methodOf 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 AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
*   - `Constructor`: a new instance of the provider will be created using
*               {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
*
* @returns {Object} registered provider instance
*/

/**

* @ngdoc method
* @name AUTO.$provide#factory
* @methodOf 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 AUTO.$provide#service
* @methodOf 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 AUTO.$provide#value
* @methodOf 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 AUTO.$provide#constant
* @methodOf AUTO.$provide
* @description
*
* A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
* into configuration function (other modules) and it is not interceptable by
* {@link AUTO.$provide#decorator decorator}.
*
* @param {string} name The name of the constant.
* @param {*} value The constant value.
* @returns {Object} registered instance
*/


/**

* @ngdoc method
* @name AUTO.$provide#decorator
* @methodOf 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 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 = annotate(fn),
         length, i,
         key;
     for(i = 0, length = $inject.length; i < length; i++) {
       key = $inject[i];
       args.push(
         locals && locals.hasOwnProperty(key)
         ? locals[key]
         : getService(key, path)
       );
     }
     if (!fn.$inject) {
       // this means that we must be an array.
       fn = fn[length];
     }


     // 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,
     annotate: annotate
   };
 }

} /**

* @ngdoc function
* @name 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 autoScrollWatch() {return $location.hash();},
       function autoScrollWatchAction() {
         $rootScope.$evalAsync(scroll);
       });
   }
   return scroll;
 }];

}

/**

* ! This is a private undocumented service !
*
* @name 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 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 {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, $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;
 /**
  * @name ng.$browser#addPollFn
  * @methodOf 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,
     baseElement = document.find('base');
 /**
  * @name ng.$browser#url
  * @methodOf 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 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) {
     if (lastBrowserUrl == url) return;
     lastBrowserUrl = url;
     if ($sniffer.history) {
       if (replace) history.replaceState(null, , url);
       else {
         history.pushState(null, , url);
         // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
         baseElement.attr('href', baseElement.attr('href'));
       }
     } else {
       if (replace) location.replace(url);
       else location.href = url;
     }
     return self;
   // getter
   } else {
     // the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
     return location.href.replace(/%27/g,"'");
   }
 };
 var urlChangeListeners = [],
     urlChangeInit = false;
 function fireUrlChange() {
   if (lastBrowserUrl == self.url()) return;
   lastBrowserUrl = self.url();
   forEach(urlChangeListeners, function(listener) {
     listener(self.url());
   });
 }
 /**
  * @name ng.$browser#onUrlChange
  * @methodOf 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 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;
 };
 //////////////////////////////////////////////////////////////
 // Misc API
 //////////////////////////////////////////////////////////////
 /**
  * Returns current <base href>
  * (always relative - without domain)
  *
  * @returns {string=}
  */
 self.baseHref = function() {
   var href = baseElement.attr('href');
   return href ? href.replace(/^https?\:\/\/[^\/]*/, ) : href;
 };
 //////////////////////////////////////////////////////////////
 // Cookies API
 //////////////////////////////////////////////////////////////
 var lastCookies = {};
 var lastCookieString = ;
 var cookiePath = self.baseHref();
 /**
  * @name ng.$browser#cookies
  * @methodOf 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:
*
    *
  • cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it
  • *
  • cookies(name, value) -> set name to value, if value is undefined delete the cookie
  • *
  • cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)
  • *
  *
  * @returns {Object} Hash of all cookies (if called without any parameter)
  */
 self.cookies = function(name, value) {
   var cookieLength, cookieArray, cookie, i, index;
   if (name) {
     if (value === undefined) {
       rawDocument.cookie = escape(name) + "=;path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
     } else {
       if (isString(value)) {
         cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).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;
   }
 };


 /**
  * @name ng.$browser#defer
  * @methodOf 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;
 };


 /**
  * @name ng.$browser#defer.cancel
  * @methodOf 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;
 };

}

function $BrowserProvider(){

 this.$get = ['$window', '$log', '$sniffer', '$document',
     function( $window,   $log,   $sniffer,   $document){
       return new Browser($window, $document, $log, $sniffer);
     }];

} /**

* @ngdoc object
* @name 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.
* - `hh` `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) return;
         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;
 };

}

/**

* @ngdoc object
* @name ng.$templateCache
*
* @description
* Cache used for storing html templates.
*
* See {@link ng.$cacheFactory $cacheFactory}.
*
*/

function $TemplateCacheProvider() {

 this.$get = ['$cacheFactory', function($cacheFactory) {
   return $cacheFactory('templates');
 }];

}

/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!

*
* DOM-related variables:
*
* - "node" - DOM Node
* - "element" - DOM Element or Node
* - "$node" or "$element" - jqLite-wrapped node or element
*
*
* Compiler related stuff:
*
* - "linkFn" - linking fn of a single directive
* - "nodeLinkFn" - function that aggregates all linking fns for a particular node
* - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
* - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
*/


var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: ';


/**

* @ngdoc function
* @name 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 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 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 ng.directive:ngRepeat 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 Template:Name';
     }
   </script>
     <input ng-model="name"> 
<textarea ng-model="html"></textarea>
  </doc:source>
  <doc:scenario>
    it('should auto compile', function() {
      expect(element('div[compile]').text()).toBe('Hello Angular');
      input('html').enter('Template: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 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: 
`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 updated 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.
*
 *     var element = $compile('<p>{{total}}</p>')(scope);
 *   
*
* - 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:
*
 *     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`
 *   
*
*
* For information on how the compiler works, see the
* {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
*/


/**

* @ngdoc service
* @name ng.$compileProvider
* @function
*
* @description
*/

$CompileProvider.$inject = ['$provide']; function $CompileProvider($provide) {

 var hasDirectives = {},
     Suffix = 'Directive',
     COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
     CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
     MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ';


 /**
  * @ngdoc function
  * @name ng.$compileProvider#directive
  * @methodOf ng.$compileProvider
  * @function
  *
  * @description
  * Register a new directives with the compiler.
  *
  * @param {string} name Name of the directive in camel-case. (ie ngBind which will match as
  *                ng-bind).
  * @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
  *                info.
  * @returns {ng.$compileProvider} Self for chaining.
  */
  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', '$rootScope',
   function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
            $controller,   $rootScope) {
   var Attributes = function(element, attr) {
     this.$$element = element;
     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 = getBooleanAttrName(this.$$element[0], key),
           $$observers = this.$$observers;
       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
       $$observers && forEach($$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.
      * @returns {function(*)} the `fn` Function passed in.
      */
     $observe: function(key, fn) {
       var attrs = this,
           $$observers = (attrs.$$observers || (attrs.$$observers = {})),
           listeners = ($$observers[key] || ($$observers[key] = []));
       listeners.push(fn);
       $rootScope.$evalAsync(function() {
         if (!listeners.$$inter) {
           // no one registered attribute interpolation function, so lets call it manually
           fn(attrs[key]);
         }
       });
       return fn;
     }
   };
   var startSymbol = $interpolate.startSymbol(),
       endSymbol = $interpolate.endSymbol(),
       denormalizeTemplate = (startSymbol == 'Template:'')
           ? identity
           : function denormalizeTemplate(template) {
             return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
           };


   return compile;
   //================================
   function compile($compileNodes, transcludeFn, maxPriority) {
     if (!($compileNodes instanceof jqLite)) {
       // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
       $compileNodes = jqLite($compileNodes);
     }
     // 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 
     forEach($compileNodes, function(node, index){
       if (node.nodeType == 3 /* text node */) {
         $compileNodes[index] = jqLite(node).wrap('').parent()[0];
       }
     });
     var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
     return function publicLinkFn(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 $linkNode = cloneConnectFn
         ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
         : $compileNodes;
       $linkNode.data('$scope', scope);
       safeAddClass($linkNode, 'ng-scope');
       if (cloneConnectFn) cloneConnectFn($linkNode, scope);
       if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
       return $linkNode;
     };
   }
   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 linkFns = [],
        nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
    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);
      nodeLinkFn = (directives.length)
          ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
          : null;
      childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
          ? null
          : compileNodes(nodeList[i].childNodes,
               nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
      linkFns.push(nodeLinkFn);
      linkFns.push(childLinkFn);
      linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
    }
    // return a linking function if we have found anything, null otherwise
    return linkFnFound ? compositeLinkFn : null;
    function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
      var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn;
      for(var i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
        node = nodeList[n];
        nodeLinkFn = linkFns[i++];
        childLinkFn = linkFns[i++];
        if (nodeLinkFn) {
          if (nodeLinkFn.scope) {
            childScope = scope.$new(isObject(nodeLinkFn.scope));
            jqLite(node).data('$scope', childScope);
          } else {
            childScope = scope;
          }
          childTranscludeFn = nodeLinkFn.transclude;
          if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
            nodeLinkFn(childLinkFn, childScope, node, $rootElement,
                (function(transcludeFn) {
                  return function(cloneFn) {
                    var transcludeScope = scope.$new();
                    return transcludeFn(transcludeScope, cloneFn).
                        bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
                   };
                 })(childTranscludeFn || transcludeFn)
            );
          } else {
            nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
          }
        } else if (childLinkFn) {
          childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
        }
      }
    }
  }


   /**
    * Looks for directives on the given node and adds 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=} maxPriority 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 (getBooleanAttrName(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) && 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 */
         try {
           match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
           if (match) {
             nName = directiveNormalize(match[1]);
             if (addDirective(directives, nName, 'M', maxPriority)) {
               attrs[nName] = trim(match[2]);
             }
           }
         } catch (e) {
           // turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
           // Just ignore it and continue. (Can't seem to reproduce in test case.)
         }
         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} compileNode 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 linkFn
    */
   function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) {
     var terminalPriority = -Number.MAX_VALUE,
         preLinkFns = [],
         postLinkFns = [],
         newScopeDirective = null,
         newIsolateScopeDirective = null,
         templateDirective = null,
         $compileNode = templateAttrs.$$element = jqLite(compileNode),
         directive,
         directiveName,
         $template,
         transcludeDirective,
         childTranscludeFn = transcludeFn,
         controllerDirectives,
         linkFn,
         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', newIsolateScopeDirective, directive, $compileNode);
         if (isObject(directiveValue)) {
           safeAddClass($compileNode, 'ng-isolate-scope');
           newIsolateScopeDirective = directive;
         }
         safeAddClass($compileNode, 'ng-scope');
         newScopeDirective = newScopeDirective || directive;
       }
       directiveName = directive.name;
       if (directiveValue = directive.controller) {
         controllerDirectives = controllerDirectives || {};
         assertNoDuplicate("'" + directiveName + "' controller",
             controllerDirectives[directiveName], directive, $compileNode);
         controllerDirectives[directiveName] = directive;
       }
       if (directiveValue = directive.transclude) {
         assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
         transcludeDirective = directive;
         terminalPriority = directive.priority;
         if (directiveValue == 'element') {
           $template = jqLite(compileNode);
           $compileNode = templateAttrs.$$element =
               jqLite();
           compileNode = $compileNode[0];
           replaceWith($rootElement, jqLite($template[0]), compileNode);
           childTranscludeFn = compile($template, transcludeFn, terminalPriority);
         } else {
           $template = jqLite(JQLiteClone(compileNode)).contents();
           $compileNode.html(); // clear contents
           childTranscludeFn = compile($template, transcludeFn);
         }
       }
       if ((directiveValue = directive.template)) {
         assertNoDuplicate('template', templateDirective, directive, $compileNode);
         templateDirective = directive;
         directiveValue = denormalizeTemplate(directiveValue);
         if (directive.replace) {
$template = jqLite('
' +
                                trim(directiveValue) +
'
').contents();
           compileNode = $template[0];
           if ($template.length != 1 || compileNode.nodeType !== 1) {
             throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
           }
           replaceWith($rootElement, $compileNode, compileNode);
           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(
                   compileNode,
                   directives.splice(i + 1, directives.length - (i + 1)),
                   newTemplateAttrs
               )
           );
           mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
           ii = directives.length;
         } else {
           $compileNode.html(directiveValue);
         }
       }
       if (directive.templateUrl) {
         assertNoDuplicate('template', templateDirective, directive, $compileNode);
         templateDirective = directive;
         nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
             nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace,
             childTranscludeFn);
         ii = directives.length;
       } else if (directive.compile) {
         try {
           linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
           if (isFunction(linkFn)) {
             addLinkFns(null, linkFn);
           } else if (linkFn) {
             addLinkFns(linkFn.pre, linkFn.post);
           }
         } catch (e) {
           $exceptionHandler(e, startingTag($compileNode));
         }
       }
       if (directive.terminal) {
         nodeLinkFn.terminal = true;
         terminalPriority = Math.max(terminalPriority, directive.priority);
       }
     }
     nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
     nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
     // might be normal or delayed nodeLinkFn depending on if templateUrl is present
     return nodeLinkFn;
     ////////////////////
     function addLinkFns(pre, post) {
       if (pre) {
         pre.require = directive.require;
         preLinkFns.push(pre);
       }
       if (post) {
         post.require = directive.require;
         postLinkFns.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;
     }


     function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
       var attrs, $element, i, ii, linkFn, controller;
       if (compileNode === linkNode) {
         attrs = templateAttrs;
       } else {
         attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
       }
       $element = attrs.$$element;
       if (newIsolateScopeDirective) {
         var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
         var parentScope = scope.$parent || scope;
         forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
           var match = definiton.match(LOCAL_REGEXP) || [],
               attrName = match[2]|| scopeName,
               mode = match[1], // @, =, or &
               lastValue,
               parentGet, parentSet;
           switch (mode) {
             case '@': {
               attrs.$observe(attrName, function(value) {
                 scope[scopeName] = value;
               });
               attrs.$$observers[attrName].$$scope = parentScope;
               break;
             }
             case '=': {
               parentGet = $parse(attrs[attrName]);
               parentSet = parentGet.assign || function() {
                 // reset the change, or we will throw this exception on every $digest
                 lastValue = scope[scopeName] = parentGet(parentScope);
                 throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
                     ' (directive: ' + newIsolateScopeDirective.name + ')');
               };
               lastValue = scope[scopeName] = parentGet(parentScope);
               scope.$watch(function parentValueWatch() {
                 var parentValue = parentGet(parentScope);
                 if (parentValue !== scope[scopeName]) {
                   // we are out of sync and need to copy
                   if (parentValue !== lastValue) {
                     // parent changed and it has precedence
                     lastValue = scope[scopeName] = parentValue;
                   } else {
                     // if the parent can be assigned then do so
                     parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
                   }
                 }
                 return parentValue;
               });
               break;
             }
             case '&': {
               parentGet = $parse(attrs[attrName]);
               scope[scopeName] = function(locals) {
                 return parentGet(parentScope, locals);
               }
               break;
             }
             default: {
               throw Error('Invalid isolate scope definition for directive ' +
                   newIsolateScopeDirective.name + ': ' + definiton);
             }
           }
         });
       }
       if (controllerDirectives) {
         forEach(controllerDirectives, function(directive) {
           var locals = {
             $scope: scope,
             $element: $element,
             $attrs: attrs,
             $transclude: boundTranscludeFn
           };
           controller = directive.controller;
           if (controller == '@') {
             controller = attrs[directive.name];
           }
           $element.data(
               '$' + directive.name + 'Controller',
               $controller(controller, locals));
         });
       }
       // PRELINKING
       for(i = 0, ii = preLinkFns.length; i < ii; i++) {
         try {
           linkFn = preLinkFns[i];
           linkFn(scope, $element, attrs,
               linkFn.require && getControllers(linkFn.require, $element));
         } catch (e) {
           $exceptionHandler(e, startingTag($element));
         }
       }
       // RECURSION
       childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
       // POSTLINKING
       for(i = 0, ii = postLinkFns.length; i < ii; i++) {
         try {
           linkFn = postLinkFns[i];
           linkFn(scope, $element, attrs,
               linkFn.require && getControllers(linkFn.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);
         dst['class'] = (dst['class'] ? dst['class'] + ' ' : ) + 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, beforeTemplateNodeLinkFn, $compileNode, tAttrs,
       $rootElement, replace, childTranscludeFn) {
     var linkQueue = [],
         afterTemplateNodeLinkFn,
         afterTemplateChildLinkFn,
         beforeTemplateCompileNode = $compileNode[0],
         origAsyncDirective = directives.shift(),
         // The fact that we have to copy and patch the directive seems wrong!
         derivedSyncDirective = extend({}, origAsyncDirective, {
           controller: null, templateUrl: null, transclude: null, scope: null
         });
     $compileNode.html();
     $http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
       success(function(content) {
         var compileNode, tempTemplateAttrs, $template;
         content = denormalizeTemplate(content);
         if (replace) {
$template = jqLite('
' + trim(content) + '
').contents();
           compileNode = $template[0];
           if ($template.length != 1 || compileNode.nodeType !== 1) {
             throw new Error(MULTI_ROOT_TEMPLATE_ERROR + content);
           }
           tempTemplateAttrs = {$attr: {}};
           replaceWith($rootElement, $compileNode, compileNode);
           collectDirectives(compileNode, directives, tempTemplateAttrs);
           mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
         } else {
           compileNode = beforeTemplateCompileNode;
           $compileNode.html(content);
         }
         directives.unshift(derivedSyncDirective);
         afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, tAttrs, childTranscludeFn);
         afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);


         while(linkQueue.length) {
           var controller = linkQueue.pop(),
               linkRootElement = linkQueue.pop(),
               beforeTemplateLinkNode = linkQueue.pop(),
               scope = linkQueue.pop(),
               linkNode = compileNode;
           if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
             // it was cloned therefore we have to clone as well.
             linkNode = JQLiteClone(compileNode);
             replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
           }
           afterTemplateNodeLinkFn(function() {
             beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
           }, scope, linkNode, $rootElement, controller);
         }
         linkQueue = null;
       }).
       error(function(response, code, headers, config) {
         throw Error('Failed to load template: ' + config.url);
       });
     return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
       if (linkQueue) {
         linkQueue.push(scope);
         linkQueue.push(node);
         linkQueue.push(rootElement);
         linkQueue.push(controller);
       } else {
         afterTemplateNodeLinkFn(function() {
           beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, 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 textInterpolateLinkFn(scope, node) {
           var parent = node.parent(),
               bindings = parent.data('$binding') || [];
           bindings.push(interpolateFn);
           safeAddClass(parent.data('$binding', bindings), 'ng-binding');
           scope.$watch(interpolateFn, function interpolateFnWatchAction(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 attrInterpolateLinkFn(scope, element, attr) {
         var $$observers = (attr.$$observers || (attr.$$observers = {}));
         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);
         }
         attr[name] = undefined;
         ($$observers[name] || ($$observers[name] = [])).$$inter = true;
         (attr.$$observers && attr.$$observers[name].$$scope || scope).
           $watch(interpolateFn, function interpolateFnWatchAction(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;
           break;
         }
       }
     }
     if (parent) {
       parent.replaceChild(newNode, oldNode);
     }
     newNode[jqLite.expando] = oldNode[jqLite.expando];
     $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, ));

}

/**

* @ngdoc object
* @name ng.$compile.directive.Attributes
* @description
*
* A shared object between directive compile / linking functions which contains normalized DOM element
* attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
* since all of these are treated as equivalent in Angular:
*
*          
*/

/**

* @ngdoc property
* @name ng.$compile.directive.Attributes#$attr
* @propertyOf ng.$compile.directive.Attributes
* @returns {object} A map of DOM element attribute names to the normalized name. This is
*          needed to do reverse lookup from normalized name back to actual name.
*/


/**

* @ngdoc function
* @name ng.$compile.directive.Attributes#$set
* @methodOf ng.$compile.directive.Attributes
* @function
*
* @description
* Set DOM element attribute value.
*
*
* @param {string} name Normalized element attribute name of the property to modify. The name is
*          revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
*          property to the original name.
* @param {string} value Value to set the attribute to.
*/


/**

* 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 ng.$controllerProvider
* @description
* The {@link ng.$controller $controller service} is used by Angular to create new
* controllers.
*
* This provider allows controller registration via the
* {@link ng.$controllerProvider#register register} method.
*/

function $ControllerProvider() {

 var controllers = {};


 /**
  * @ngdoc function
  * @name ng.$controllerProvider#register
  * @methodOf 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) {
   if (isObject(name)) {
     extend(controllers, name)
   } else {
     controllers[name] = constructor;
   }
 };


 this.$get = ['$injector', '$window', function($injector, $window) {
   /**
    * @ngdoc function
    * @name 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 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 object
* @name 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 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 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 object
* @name ng.$interpolateProvider
* @function
*
* @description
*
* Used for configuring the interpolation markup. Defaults to `Template:` and ``.
*/

function $InterpolateProvider() {

 var startSymbol = '{{';
 var endSymbol = '}}';
 /**
  * @ngdoc method
  * @name ng.$interpolateProvider#startSymbol
  * @methodOf ng.$interpolateProvider
  * @description
  * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
  *
  * @param {string=} value new value to set the starting symbol to.
  * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
  */
 this.startSymbol = function(value){
   if (value) {
     startSymbol = value;
     return this;
   } else {
     return startSymbol;
   }
 };
 /**
  * @ngdoc method
  * @name ng.$interpolateProvider#endSymbol
  * @methodOf ng.$interpolateProvider
  * @description
  * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
  *
  * @param {string=} value new value to set the ending symbol to.
  * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
  */
 this.endSymbol = function(value){
   if (value) {
     endSymbol = value;
     return this;
   } else {
     return endSymbol;
   }
 };


 this.$get = ['$parse', function($parse) {
   var startSymbolLength = startSymbol.length,
       endSymbolLength = endSymbol.length;
   /**
    * @ngdoc function
    * @name ng.$interpolate
    * @function
    *
    * @requires $parse
    *
    * @description
    *
    * Compiles a string with markup into an interpolation function. This service is used by the
    * HTML {@link ng.$compile $compile} service for data binding. See
    * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
    * interpolation markup.
    *
    *
         var $interpolate = ...; // injected
         var exp = $interpolate('Hello {{name}}!');
         expect(exp({name:'Angular'}).toEqual('Hello Angular!');
       
    *
    *
    * @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.
    *
    */
   function $interpolate(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;
     }
   }


   /**
    * @ngdoc method
    * @name ng.$interpolate#startSymbol
    * @methodOf ng.$interpolate
    * @description
    * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
    *
    * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
    * the symbol.
    *
    * @returns {string} start symbol.
    */
   $interpolate.startSymbol = function() {
     return startSymbol;
   }


   /**
    * @ngdoc method
    * @name ng.$interpolate#endSymbol
    * @methodOf ng.$interpolate
    * @description
    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
    *
    * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
    * the symbol.
    *
    * @returns {string} start symbol.
    */
   $interpolate.endSymbol = function() {
     return endSymbol;
   }
   return $interpolate;
 }];

}

var URL_MATCH = /^([^:]+):\/\/(\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 stripHash(url) {

 return url.split('#')[0];

}


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 Error('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, appBaseUrl) {

 pathPrefix = pathPrefix || ;
 /**
  * Parse given html5 (regular) url string into properties
  * @param {string} newAbsoluteUrl HTML5 url
  * @private
  */
 this.$$parse = function(newAbsoluteUrl) {
   var match = matchUrl(newAbsoluteUrl, this);
   if (match.path.indexOf(pathPrefix) !== 0) {
     throw Error('Invalid url "' + newAbsoluteUrl + '", 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.$$rewriteAppUrl = function(absoluteLinkUrl) {
   if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
     return absoluteLinkUrl;
   }
 }


 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, appBaseUrl) {

 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 Error('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.$$rewriteAppUrl = function(absoluteLinkUrl) {
   if(absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
     return absoluteLinkUrl;
   }
 }


 this.$$parse(url);

}


LocationUrl.prototype = {

 /**
  * Has any change been replacing ?
  * @private
  */
 $$replace: false,
 /**
  * @ngdoc method
  * @name ng.$location#absUrl
  * @methodOf 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} full url
  */
 absUrl: locationGetter('$$absUrl'),
 /**
  * @ngdoc method
  * @name ng.$location#url
  * @methodOf 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
  */
 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 ng.$location#protocol
  * @methodOf ng.$location
  *
  * @description
  * This method is getter only.
  *
  * Return protocol of current url.
  *
  * @return {string} protocol of current url
  */
 protocol: locationGetter('$$protocol'),
 /**
  * @ngdoc method
  * @name ng.$location#host
  * @methodOf ng.$location
  *
  * @description
  * This method is getter only.
  *
  * Return host of current url.
  *
  * @return {string} host of current url.
  */
 host: locationGetter('$$host'),
 /**
  * @ngdoc method
  * @name ng.$location#port
  * @methodOf ng.$location
  *
  * @description
  * This method is getter only.
  *
  * Return port of current url.
  *
  * @return {Number} port
  */
 port: locationGetter('$$port'),
 /**
  * @ngdoc method
  * @name ng.$location#path
  * @methodOf 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
  */
 path: locationGetterSetter('$$path', function(path) {
   return path.charAt(0) == '/' ? path : '/' + path;
 }),
 /**
  * @ngdoc method
  * @name ng.$location#search
  * @methodOf 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
  */
 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 ng.$location#hash
  * @methodOf 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
  */
 hash: locationGetterSetter('$$hash', identity),
 /**
  * @ngdoc method
  * @name ng.$location#replace
  * @methodOf 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 LocationHashbangInHtml5Url(url, hashPrefix, appBaseUrl, baseExtra) {

 LocationHashbangUrl.apply(this, arguments);


 this.$$rewriteAppUrl = function(absoluteLinkUrl) {
   if (absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
     return appBaseUrl + baseExtra + '#' + hashPrefix  + absoluteLinkUrl.substr(appBaseUrl.length);
   }
 }

}

LocationHashbangInHtml5Url.prototype = inherit(LocationHashbangUrl.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 ng.$location
*
* @requires $browser
* @requires $sniffer
* @requires $rootElement
*
* @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 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 ng.$locationProvider#hashPrefix
  * @methodOf 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 ng.$locationProvider#html5Mode
  * @methodOf 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', '$rootElement',
     function( $rootScope,   $browser,   $sniffer,   $rootElement) {
   var $location,
       basePath,
       pathPrefix,
       initUrl = $browser.url(),
       initUrlParts = matchUrl(initUrl),
       appBaseUrl;
   if (html5Mode) {
     basePath = $browser.baseHref() || '/';
     pathPrefix = pathPrefixFromBase(basePath);
     appBaseUrl =
         composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
         pathPrefix + '/';
     if ($sniffer.history) {
       $location = new LocationUrl(
         convertToHtml5Url(initUrl, basePath, hashPrefix),
         pathPrefix, appBaseUrl);
     } else {
       $location = new LocationHashbangInHtml5Url(
         convertToHashbangUrl(initUrl, basePath, hashPrefix),
         hashPrefix, appBaseUrl, basePath.substr(pathPrefix.length + 1));
     }
   } else {
     appBaseUrl =
         composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
         (initUrlParts.path || ) +
         (initUrlParts.search ? ('?' + initUrlParts.search) : ) +
         '#' + hashPrefix + '/';
     $location = new LocationHashbangUrl(initUrl, hashPrefix, appBaseUrl);
   }
   $rootElement.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 (lowercase(elm[0].nodeName) !== 'a') {
       // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
       if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
     }
     var absHref = elm.prop('href'),
         rewrittenUrl = $location.$$rewriteAppUrl(absHref);
     if (absHref && !elm.attr('target') && rewrittenUrl) {
       // update location manually
       $location.$$parse(rewrittenUrl);
       $rootScope.$apply();
       event.preventDefault();
       // hack to work around FF6 bug 684208 when scenario runner clicks on links
       window.angular['ff-684208-preventDefault'] = true;
     }
   });


   // rewrite hashbang url <> html5 url
   if ($location.absUrl() != initUrl) {
     $browser.url($location.absUrl(), true);
   }
   // update $location when $browser url changes
   $browser.onUrlChange(function(newUrl) {
     if ($location.absUrl() != newUrl) {
       $rootScope.$evalAsync(function() {
         var oldUrl = $location.absUrl();
         $location.$$parse(newUrl);
         afterLocationChange(oldUrl);
       });
       if (!$rootScope.$$phase) $rootScope.$digest();
     }
   });
   // update browser
   var changeCounter = 0;
   $rootScope.$watch(function $locationWatch() {
     var oldUrl = $browser.url();
     var currentReplace = $location.$$replace;
     if (!changeCounter || oldUrl != $location.absUrl()) {
       changeCounter++;
       $rootScope.$evalAsync(function() {
         if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
             defaultPrevented) {
           $location.$$parse(oldUrl);
         } else {
           $browser.url($location.absUrl(), currentReplace);
           afterLocationChange(oldUrl);
         }
       });
     }
     $location.$$replace = false;
     return changeCounter;
   });
   return $location;
   function afterLocationChange(oldUrl) {
     $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
   }

}]; }

/**

* @ngdoc object
* @name 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
  <example>
    <file name="script.js">
      function LogCtrl($scope, $log) {
        $scope.$log = $log;
        $scope.message = 'Hello World!';
      }
    </file>
    <file name="index.html">

Reload this page with open console, enter text and hit the log button...

        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>
    </file>
  </example>
*/

function $LogProvider(){

 this.$get = ['$window', function($window){
   return {
     /**
      * @ngdoc method
      * @name ng.$log#log
      * @methodOf ng.$log
      *
      * @description
      * Write a log message
      */
     log: consoleLog('log'),
     /**
      * @ngdoc method
      * @name ng.$log#warn
      * @methodOf ng.$log
      *
      * @description
      * Write a warning message
      */
     warn: consoleLog('warn'),
     /**
      * @ngdoc method
      * @name ng.$log#info
      * @methodOf ng.$log
      *
      * @description
      * Write an information message
      */
     info: consoleLog('info'),
     /**
      * @ngdoc method
      * @name ng.$log#error
      * @methodOf 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);
     if (isDefined(a)) {
       if (isDefined(b)) {
         return a + b;
       }
       return a;
     }
     return isDefined(b)?b:undefined;},
   '-':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, csp){

 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, csp);
     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, csp){

 var ZERO = valueFn(0),
     value,
     tokens = lex(text, csp),
     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 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 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, csp);
   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 = {};

/**

* Implementation of the "Black Hole" variant from:
* - http://jsperf.com/angularjs-parse-getter/4
* - http://jsperf.com/path-evaluation-simplified/7
*/

function cspSafeGetterFn(key0, key1, key2, key3, key4) {

 return function(scope, locals) {
   var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
       promise;
   if (pathVal === null || pathVal === undefined) return pathVal;
   pathVal = pathVal[key0];
   if (pathVal && pathVal.then) {
     if (!("$$v" in pathVal)) {
       promise = pathVal;
       promise.$$v = undefined;
       promise.then(function(val) { promise.$$v = val; });
     }
     pathVal = pathVal.$$v;
   }
   if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
   pathVal = pathVal[key1];
   if (pathVal && pathVal.then) {
     if (!("$$v" in pathVal)) {
       promise = pathVal;
       promise.$$v = undefined;
       promise.then(function(val) { promise.$$v = val; });
     }
     pathVal = pathVal.$$v;
   }
   if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
   pathVal = pathVal[key2];
   if (pathVal && pathVal.then) {
     if (!("$$v" in pathVal)) {
       promise = pathVal;
       promise.$$v = undefined;
       promise.then(function(val) { promise.$$v = val; });
     }
     pathVal = pathVal.$$v;
   }
   if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
   pathVal = pathVal[key3];
   if (pathVal && pathVal.then) {
     if (!("$$v" in pathVal)) {
       promise = pathVal;
       promise.$$v = undefined;
       promise.then(function(val) { promise.$$v = val; });
     }
     pathVal = pathVal.$$v;
   }
   if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
   pathVal = pathVal[key4];
   if (pathVal && pathVal.then) {
     if (!("$$v" in pathVal)) {
       promise = pathVal;
       promise.$$v = undefined;
       promise.then(function(val) { promise.$$v = val; });
     }
     pathVal = pathVal.$$v;
   }
   return pathVal;
 };

};

function getterFn(path, csp) {

 if (getterFnCache.hasOwnProperty(path)) {
   return getterFnCache[path];
 }
 var pathKeys = path.split('.'),
     pathKeysLength = pathKeys.length,
     fn;
 if (csp) {
   fn = (pathKeysLength < 6)
       ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
       : function(scope, locals) {
         var i = 0, val
         do {
           val = cspSafeGetterFn(
                   pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
                 )(scope, locals);
           locals = undefined; // clear after first iteration
           scope = val;
         } while (i < pathKeysLength);
         return val;
       }
 } else {
   var code = 'var l, fn, p;\n';
   forEach(pathKeys, function(key, index) {
     code += 'if(s === null || s === undefined) return s;\n' +
             'l=s;\n' +
             's='+ (index
                     // we simply dereference 's' on any .dot notation
                     ? 's'
                     // but if we are first then we check locals first, 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); // s=scope, k=locals
   fn.toString = function() { return code; };
 }
 return getterFnCache[path] = fn;

}

///////////////////////////////////

/**

* @ngdoc function
* @name ng.$parse
* @function
*
* @description
*
* Converts Angular {@link guide/expression expression} into a function.
*
*
 *   var getter = $parse('user.name');
 *   var setter = getter.assign;
 *   var context = {user:{name:'angular'}};
 *   var locals = {user:{name:'local'}};
 *
 *   expect(getter(context)).toEqual('angular');
 *   setter(context, 'newValue');
 *   expect(context.user.name).toEqual('newValue');
 *   expect(getter(context, locals)).toEqual('local');
 * 
*
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
*    * `context`: an object against which any expressions embedded in the strings are evaluated
*      against (Topically a scope object).
*    * `locals`: local variables context object, useful for overriding values in `context`.
*
*    The return function also has an `assign` property, if the expression is assignable, which
*    allows one to set values to expressions.
*
*/

function $ParseProvider() {

 var cache = {};
 this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
   return function(exp) {
     switch(typeof exp) {
       case 'string':
         return cache.hasOwnProperty(exp)
           ? cache[exp]
           : cache[exp] =  parser(exp, false, $filter, $sniffer.csp);
       case 'function':
         return exp;
       default:
         return noop;
     }
   };
 }];

}

/**

* @ngdoc service
* @name 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.
*
*
 *   // 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);
 *   });
 * 
*
* 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:
*
*
 *   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
 * 
*
* 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 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 ng.$q#defer
  * @methodOf 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 ng.$q#reject
  * @methodOf 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`.
  *
*
   *   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);
   *   });
   * 
  *
  * @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 ng.$q#when
  * @methodOf 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 ng.$q#all
  * @methodOf 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 ng.$routeProvider
* @function
*
* @description
*
* Used for configuring routes. See {@link ng.$route $route} for an example.
*/

function $RouteProvider(){

 var routes = {};
 /**
  * @ngdoc method
  * @name ng.$routeProvider#when
  * @methodOf ng.$routeProvider
  *
  * @param {string} path Route path (matched against `$location.path`). If `$location.path`
  *    contains redundant 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` – `{(string|function()=}` – Controller fn that should be associated with newly
  *      created scope or the name of a {@link angular.Module#controller registered controller}
  *      if passed as a string.
  *    - `template` – `{string=}` –  html template as a string that should be used by
  *      {@link ng.directive:ngView ngView} or
  *      {@link ng.directive:ngInclude ngInclude} directives.
  *      this property takes precedence over `templateUrl`.
  *    - `templateUrl` – `{string=}` – path to an html template that should be used by
  *      {@link ng.directive:ngView ngView}.
  *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
  *      be injected into the controller. If any of these dependencies are promises, they will be
  *      resolved and converted to a value before the controller is instantiated and the
  *      `$routeChangeSuccess` event is fired. The map object is:
  *
  *      - `key` – `{string}`: a name of a dependency to be injected into the controller.
  *      - `factory` - `{string|function}`: If `string` then it is an alias for a service.
  *        Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
  *        and the return value is treated as the dependency. If the result is a promise, it is resolved
  *        before its value is injected into the controller.
  *
  *    - `redirectTo` – {(string|function())=} – value to update
  *      {@link 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 templateUrl.
  *      - `{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 ng.$routeProvider#otherwise
  * @methodOf 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', '$q', '$injector', '$http', '$templateCache',
     function( $rootScope,   $location,   $routeParams,   $q,   $injector,   $http,   $templateCache) {
   /**
    * @ngdoc object
    * @name ng.$route
    * @requires $location
    * @requires $routeParams
    *
    * @property {Object} current Reference to the current route definition.
    * The route definition contains:
    *
    *   - `controller`: The controller constructor as define in route definition.
    *   - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
    *     controller instantiation. The `locals` contain
    *     the resolved values of the `resolve` map. Additionally the `locals` also contain:
    *
    *     - `$scope` - The current route scope.
    *     - `$template` - The current route template HTML.
    *
    * @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 ng.$routeProvider $routeProvider}'s API.
    *
    * The `$route` service is typically used in conjunction with {@link ng.directive:ngView ngView}
    * directive and the {@link 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 `ngView` pulls in the partial.
      Note that this example is using {@link ng.directive:script inlined templates}
      to get it working on jsfiddle as well.
    <example module="ngView">
      <file name="index.html">
          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>

$location.path() = {{$location.path()}}
$route.current.templateUrl = {{$route.current.templateUrl}}
$route.current.params = {{$route.current.params}}
$route.current.scope.name = {{$route.current.scope.name}}
$routeParams = {{$routeParams}}
      </file>
      <file name="book.html">
        controller: Template:Name
Book Id: Template:Params.bookId
</file>
      <file name="chapter.html">
        controller: Template:Name
Book Id: Template:Params.bookId
Chapter Id: Template:Params.chapterId </file>
      <file name="script.js">
        angular.module('ngView', [], function($routeProvider, $locationProvider) {
          $routeProvider.when('/Book/:bookId', {
            templateUrl: 'book.html',
            controller: BookCntl,
            resolve: {
              // I will cause a 1 second delay
              delay: function($q, $timeout) {
                var delay = $q.defer();
                $timeout(delay.resolve, 1000);
                return delay.promise;
              }
            }
          });
          $routeProvider.when('/Book/:bookId/ch/:chapterId', {
            templateUrl: '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;
        }
      </file>
      <file name="scenario.js">
        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();
          sleep(2); // promises are not part of scenario waiting
          content = element('.doc-example-live [ng-view]').text();
          expect(content).toMatch(/controller\: BookCntl/);
          expect(content).toMatch(/Book Id\: Scarlet/);
        });
      </file>
    </example>
    */
   /**
    * @ngdoc event
    * @name ng.$route#$routeChangeStart
    * @eventOf ng.$route
    * @eventType broadcast on root scope
    * @description
    * Broadcasted before a route change. At this  point the route services starts
    * resolving all of the dependencies needed for the route change to occurs.
    * Typically this involves fetching the view template as well as any dependencies
    * defined in `resolve` route property. Once  all of the dependencies are resolved
    * `$routeChangeSuccess` is fired.
    *
    * @param {Route} next Future route information.
    * @param {Route} current Current route information.
    */
   /**
    * @ngdoc event
    * @name ng.$route#$routeChangeSuccess
    * @eventOf ng.$route
    * @eventType broadcast on root scope
    * @description
    * Broadcasted after a route dependencies are resolved.
    * {@link ng.directive:ngView ngView} listens for the directive
    * to instantiate the controller and render the view.
    *
    * @param {Route} current Current route information.
    * @param {Route} previous Previous route information.
    */
   /**
    * @ngdoc event
    * @name ng.$route#$routeChangeError
    * @eventOf ng.$route
    * @eventType broadcast on root scope
    * @description
    * Broadcasted if any of the resolve promises are rejected.
    *
    * @param {Route} current Current route information.
    * @param {Route} previous Previous route information.
    * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
    */
   /**
    * @ngdoc event
    * @name ng.$route#$routeUpdate
    * @eventOf 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,
       forceReload = false,
       $route = {
         routes: routes,
         /**
          * @ngdoc method
          * @name ng.$route#reload
          * @methodOf ng.$route
          *
          * @description
          * Causes `$route` service to reload the current route even if
          * {@link ng.$location $location} hasn't changed.
          *
          * As a result of that, {@link ng.directive:ngView ngView}
          * creates new scope, reinstantiates the controller.
          */
         reload: function() {
           forceReload = true;
           $rootScope.$evalAsync(updateRoute);
         }
       };
   $rootScope.$on('$locationChangeSuccess', 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('$routeChangeStart', 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();
           }
         }
       }
       $q.when(next).
         then(function() {
           if (next) {
             var keys = [],
                 values = [],
                 template;
             forEach(next.resolve || {}, function(value, key) {
               keys.push(key);
               values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
             });
             if (isDefined(template = next.template)) {
             } else if (isDefined(template = next.templateUrl)) {
               template = $http.get(template, {cache: $templateCache}).
                   then(function(response) { return response.data; });
             }
             if (isDefined(template)) {
               keys.push('$template');
               values.push(template);
             }
             return $q.all(values).then(function(values) {
               var locals = {};
               forEach(values, function(value, index) {
                 locals[keys[index]] = value;
               });
               return locals;
             });
           }
         }).
         // after route change
         then(function(locals) {
           if (next == $route.current) {
             if (next) {
               next.locals = locals;
               copy(next.params, $routeParams);
             }
             $rootScope.$broadcast('$routeChangeSuccess', next, last);
           }
         }, function(error) {
           if (next == $route.current) {
             $rootScope.$broadcast('$routeChangeError', next, last, error);
           }
         });
     }
   }


   /**
    * @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 ng.$routeParams
* @requires $route
*
* @description
* Current set of route parameters. The route parameters are a combination of the
* {@link ng.$location $location} `search()`, and `path()`. The `path` parameters
* are extracted when the {@link 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
*
 *  // 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'}
 * 
*/

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 ng.$rootScopeProvider
* @description
*
* Provider for the $rootScope service.
*/

/**

* @ngdoc function
* @name ng.$rootScopeProvider#digestTtl
* @methodOf 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 ng.$rootScope
* @description
*
* Every application has a single root {@link 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/scope 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 ng.$rootScope.Scope
    *
    * @description
    * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
    * {@link AUTO.$injector $injector}. Child scopes are created using the
    * {@link 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.
*
        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!');
        });
     * 
    *
    * # Inheritance
    * A scope can inherit from a parent scope, as in this example:
*
         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');
     * 
    *
    *
    * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
    *     for the current scope. Defaults to {@link 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 ng.$rootScope.Scope#$id
    * @propertyOf ng.$rootScope.Scope
    * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
    *   debugging.
    */


   Scope.prototype = {
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$new
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Creates a new child {@link ng.$rootScope.Scope scope}.
      *
      * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
      * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
      * hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
      *
      * {@link 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.
      *
      * @param {boolean} isolate if true then the scope does not prototypically inherit from the
      *         parent scope. The scope is isolated, as it can not see parent scope properties.
      *         When creating widgets it is useful for the widget to not accidentally 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 ng.$rootScope.Scope#$watch
      * @methodOf 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 ng.$rootScope.Scope#$digest $digest()} and
      *   should return the value which will be watched. (Since {@link ng.$rootScope.Scope#$digest $digest()}
      *   reruns when it detects changes the `watchExpression` can execute multiple times per
      *   {@link 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, the
      *   {@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 10 to prevent an infinite loop deadlock.
      *
      *
      * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
      * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
      * can execute multiple times per {@link 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 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
*
           // 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);
       * 
      *
      *
      *
      * @param {(function()|string)} watchExpression Expression that is evaluated on each
      *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
      *    call to the `listener`.
      *
      *    - `string`: Evaluated as {@link guide/expression 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/expression expression}
      *    - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
      *
      * @param {boolean=} objectEquality Compare object for equality rather than for reference.
      * @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 ng.$rootScope.Scope#$digest
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
      * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
      * `$digest()` keeps calling the {@link 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 10.
      *
      * Usually you don't call `$digest()` directly in
      * {@link ng.directive:ngController controllers} or in
      * {@link ng.$compileProvider#directive directives}.
      * Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
      * {@link 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 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
*
           var scope = ...;
           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);
       * 
      *
      */
     $digest: function() {
       var watch, value, last,
           watchers,
           asyncQueue,
           length,
           dirty, ttl = TTL,
           next, current, target = this,
           watchLog = [],
           logIdx, logMsg;
       beginPhase('$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--)) {
           clearPhase();
           throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
               'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
         }
       } while (dirty || asyncQueue.length);
       clearPhase();
     },


     /**
      * @ngdoc event
      * @name ng.$rootScope.Scope#$destroy
      * @eventOf ng.$rootScope.Scope
      * @eventType broadcast on scope being destroyed
      *
      * @description
      * Broadcasted when a scope and its children are being destroyed.
      */
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$destroy
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Removes the current scope (and all of its children) from the parent scope. Removal implies
      * that calls to {@link 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 ng.directive:ngRepeat ngRepeat} 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 ($rootScope == 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;
       // This is bogus code that works around Chrome's GC leak
       // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
       this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
           this.$$childTail = null;
     },
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$eval
      * @methodOf 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 Angular expressions.
      *
      * # Example
*
           var scope = 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);
       * 
      *
      * @param {(string|function())=} expression An angular expression to be executed.
      *
      *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
      *    - `function(scope)`: execute the function with the current `scope` parameter.
      *
      * @returns {*} The result of evaluating the expression.
      */
     $eval: function(expr, locals) {
       return $parse(expr)(this, locals);
     },
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$evalAsync
      * @methodOf 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 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 ng.$exceptionHandler $exceptionHandler} service.
      *
      * @param {(string|function())=} expression An angular expression to be executed.
      *
      *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
      *    - `function(scope)`: execute the function with the current `scope` parameter.
      *
      */
     $evalAsync: function(expr) {
       this.$$asyncQueue.push(expr);
     },
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$apply
      * @methodOf 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 ng.$exceptionHandler exception handling},
      * {@link 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/expression expression} is executed using the
      *    {@link ng.$rootScope.Scope#$eval $eval()} method.
      * 2. Any exceptions from the execution of the expression are forwarded to the
      *    {@link ng.$exceptionHandler $exceptionHandler} service.
      * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
      *    was executed using the {@link 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/expression expression}.
      *    - `function(scope)`: execute the function with current `scope` parameter.
      *
      * @returns {*} The result of evaluating the expression.
      */
     $apply: function(expr) {
       try {
         beginPhase('$apply');
         return this.$eval(expr);
       } catch (e) {
         $exceptionHandler(e);
       } finally {
         clearPhase();
         try {
           $rootScope.$digest();
         } catch (e) {
           $exceptionHandler(e);
           throw e;
         }
       }
     },
     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$on
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Listens on events of a given type. See {@link 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, args...)`. 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.
      *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
      *     propagation (available only for events that were `$emit`-ed).
      *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
      *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
      */
     $on: function(name, listener) {
       var namedListeners = this.$$listeners[name];
       if (!namedListeners) {
         this.$$listeners[name] = namedListeners = [];
       }
       namedListeners.push(listener);
       return function() {
         namedListeners[indexOf(namedListeners, listener)] = null;
       };
     },


     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$emit
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Dispatches an event `name` upwards through the scope hierarchy notifying the
      * registered {@link ng.$rootScope.Scope#$on} listeners.
      *
      * The event life cycle starts at the scope on which `$emit` was called. All
      * {@link 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 ng.$rootScope.Scope#$on listeners} will be passed
      * onto the {@link 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 ng.$rootScope.Scope#$on}
      */
     $emit: function(name, args) {
       var empty = [],
           namedListeners,
           scope = this,
           stopPropagation = false,
           event = {
             name: name,
             targetScope: scope,
             stopPropagation: function() {stopPropagation = true;},
             preventDefault: function() {
               event.defaultPrevented = true;
             },
             defaultPrevented: 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++) {
           // if listeners were deregistered, defragment the array
           if (!namedListeners[i]) {
             namedListeners.splice(i, 1);
             i--;
             length--;
             continue;
           }
           try {
             namedListeners[i].apply(null, listenerArgs);
             if (stopPropagation) return event;
           } catch (e) {
             $exceptionHandler(e);
           }
         }
         //traverse upwards
         scope = scope.$parent;
       } while (scope);
       return event;
     },


     /**
      * @ngdoc function
      * @name ng.$rootScope.Scope#$broadcast
      * @methodOf ng.$rootScope.Scope
      * @function
      *
      * @description
      * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
      * registered {@link ng.$rootScope.Scope#$on} listeners.
      *
      * The event life cycle starts at the scope on which `$broadcast` was called. All
      * {@link 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 ng.$rootScope.Scope#$on listeners} will be passed
      * onto the {@link 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 ng.$rootScope.Scope#$on}
      */
     $broadcast: function(name, args) {
       var target = this,
           current = target,
           next = target,
           event = {
             name: name,
             targetScope: target,
             preventDefault: function() {
               event.defaultPrevented = true;
             },
             defaultPrevented: false
           },
           listenerArgs = concat([event], arguments, 1),
           listeners, i, length;
       //down while you can, then up and next sibling or up and next sibling until back at root
       do {
         current = next;
         event.currentScope = current;
         listeners = current.$$listeners[name] || [];
         for (i=0, length = listeners.length; i<length; i++) {
           // if listeners were deregistered, defragment the array
           if (!listeners[i]) {
             listeners.splice(i, 1);
             i--;
             length--;
             continue;
           }
           try {
             listeners[i].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;
     }
   };
   var $rootScope = new Scope();
   return $rootScope;


   function beginPhase(phase) {
     if ($rootScope.$$phase) {
       throw Error($rootScope.$$phase + ' already in progress');
     }
     $rootScope.$$phase = phase;
   }
   function clearPhase() {
     $rootScope.$$phase = null;
   }
   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() {}
 }];

}

/**

* !!! This is an undocumented "private" service !!!
*
* @name 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 = {},
       android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
   return {
     // Android has history.pushState, but it does not update location correctly
     // so let's not use the history API at all.
     // http://code.google.com/p/android/issues/detail?id=17471
     // https://github.com/angular/angular.js/issues/904
     history: !!($window.history && $window.history.pushState && !(android < 4)),
     hashchange: 'onhashchange' in $window &&
                 // IE8 compatible mode lies
                 (!$window.document.documentMode || $window.document.documentMode > 7),
     hasEvent: function(event) {
       // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
       // it. In particular the event is not fired when backspace or delete key are pressed or
       // when cut operation is performed.
       if (event == 'input' && msie == 9) return false;
       if (isUndefined(eventSupport[event])) {
         var divElm = $window.document.createElement('div');
         eventSupport[event] = 'on' + event in divElm;
       }
       return eventSupport[event];
     },
     // TODO(i): currently there is no way to feature detect CSP without triggering alerts
     csp: false
   };
 }];

}

/**

* @ngdoc object
* @name 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;charset=utf-8'},
     put:  {'Content-Type': 'application/json;charset=utf-8'}
   }
 };
 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 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 ngMock.$httpBackend $httpBackend mock}.
    *
    * For a higher level of abstraction, please check out the {@link ngResource.$resource
    * $resource} service.
    *
    * The $http API is based on the {@link 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 ng.$q promise}
    * with two $http specific methods: `success` and `error`.
    *
*
     *   $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
     *     });
     * 
    *
    * 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:
    *
*
     *   $http.get('/someUrl').success(successCallback);
     *   $http.post('/someUrl', data).success(successCallback);
     * 
    *
    * Complete list of shortcut methods:
    *
    * - {@link ng.$http#get $http.get}
    * - {@link ng.$http#head $http.head}
    * - {@link ng.$http#post $http.post}
    * - {@link ng.$http#put $http.put}
    * - {@link ng.$http#delete $http.delete}
    * - {@link 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'`.
    *
    * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
    * fassion as described above.
    *
    *
    * # 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 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 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 ng.$q promise} and returns the original or a new promise.
    *
*
     *   // 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
     *     }
     *   });
     * 
    *
    *
    * # 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:
*
     * ['one','two']
     * 
    *
    * which is vulnerable to attack, your server can return:
*
     * )]}',
     * ['one','two']
     * 
    *
    * 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 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 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
     <example>
       <file name="index.html">
           <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>
<button ng-click="updateModel('GET', '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>
http status code: {{status}}
http response data: {{data}}
       </file>
       <file name="script.js">
         function FetchCtrl($scope, $http, $templateCache) {
           $scope.method = 'GET';
           $scope.url = 'http-hello.html';
           $scope.fetch = function() {
             $scope.code = null;
             $scope.response = null;
             $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
               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;
           };
         }
       </file>
       <file name="http-hello.html">
         Hello, $http!
       </file>
       <file name="scenario.js">
         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')).toMatch(/Hello, \$http!/);
         });
         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');
         });
       </file>
     </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 ng.$http#get
    * @methodOf 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 ng.$http#delete
    * @methodOf 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 ng.$http#head
    * @methodOf 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 {HttpPromise} Future object
    */
   /**
    * @ngdoc method
    * @name ng.$http#jsonp
    * @methodOf 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 {HttpPromise} Future object
    */
   createShortMethods('get', 'delete', 'head', 'jsonp');
   /**
    * @ngdoc method
    * @name ng.$http#post
    * @methodOf 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 ng.$http#put
    * @methodOf 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 {HttpPromise} Future object
    */
   createShortMethodsWithData('post', 'put');
       /**
        * @ngdoc property
        * @name ng.$http#defaults
        * @propertyOf ng.$http
        *
        * @description
        * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
        * default headers as well as request and response transformations.
        *
        * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
        */
   $http.defaults = $config;


   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 ng.$httpBackend
* @requires $browser
* @requires $window
* @requires $document
*
* @description
* HTTP backend used by the {@link 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 ng.$http $http} or {@link ngResource.$resource $resource}.
*
* During testing this implementation is swapped with {@link 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], $window.location.protocol.replace(':', ));
 }];

}

function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, 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;
     };
     jsonpReq(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];
     });
   } 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);
   }
 };
 function jsonpReq(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'),
       doneWrapper = function() {
         rawDocument.body.removeChild(script);
         if (done) done();
       };
   script.type = 'text/javascript';
   script.src = url;
   if (msie) {
     script.onreadystatechange = function() {
       if (/loaded|complete/.test(script.readyState)) doneWrapper();
     };
   } else {
     script.onload = script.onerror = doneWrapper;
   }
   rawDocument.body.appendChild(script);
 }

}

/**

* @ngdoc object
* @name 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';
     }
   };
 };

}

function $TimeoutProvider() {

 this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
      function($rootScope,   $browser,   $q,   $exceptionHandler) {
   var deferreds = {};


    /**
     * @ngdoc function
     * @name ng.$timeout
     * @requires $browser
     *
     * @description
     * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
     * block and delegates any exceptions to
     * {@link ng.$exceptionHandler $exceptionHandler} service.
     *
     * The return value of registering a timeout function is a promise which will be resolved when
     * the timeout is reached and the timeout function is executed.
     *
     * To cancel a the timeout request, call `$timeout.cancel(promise)`.
     *
     * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
     * synchronously flush the queue of deferred functions.
     *
     * @param {function()} fn A function, who's execution should be delayed.
     * @param {number=} [delay=0] Delay in milliseconds.
     * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
     *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
     * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
     *   promise will be resolved with is the return value of the `fn` function.
     */
   function timeout(fn, delay, invokeApply) {
     var deferred = $q.defer(),
         promise = deferred.promise,
         skipApply = (isDefined(invokeApply) && !invokeApply),
         timeoutId, cleanup;
     timeoutId = $browser.defer(function() {
       try {
         deferred.resolve(fn());
       } catch(e) {
         deferred.reject(e);
         $exceptionHandler(e);
       }
       if (!skipApply) $rootScope.$apply();
     }, delay);
     cleanup = function() {
       delete deferreds[promise.$$timeoutId];
     };
     promise.$$timeoutId = timeoutId;
     deferreds[timeoutId] = deferred;
     promise.then(cleanup, cleanup);
     return promise;
   }


    /**
     * @ngdoc function
     * @name ng.$timeout#cancel
     * @methodOf ng.$timeout
     *
     * @description
     * Cancels a task associated with the `promise`. As a result of this the promise will be
     * resolved with a rejection.
     *
     * @param {Promise=} promise Promise returned by the `$timeout` function.
     * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
     *   canceled.
     */
   timeout.cancel = function(promise) {
     if (promise && promise.$$timeoutId in deferreds) {
       deferreds[promise.$$timeoutId].reject('canceled');
       return $browser.defer.cancel(promise.$$timeoutId);
     }
     return false;
   };
   return timeout;
 }];

}

/**

* @ngdoc object
* @name 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.
*
*
 *   // 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;
 *       };
 *     });
 *   }
 * 
*
* The filter function is registered with the `$injector` under the filter name suffixe with `Filter`.
*
 *   it('should be the same instance', inject(
 *     function($filterProvider) {
 *       $filterProvider.register('reverse', function(){
 *         return ...;
 *       });
 *     },
 *     function($filter, reverseFilter) {
 *       expect($filter('reverse')).toBe(reverseFilter);
 *     });
 * 
*
*
* 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 ng.$filterProvider#register
* @methodOf 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 ng.$filter
* @function
* @description
* Filters are used for formatting data displayed to the user.
*
* The general syntax in templates is as follows:
*
*         Template:Expression
*
* @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('lowercase', lowercaseFilter);
 register('number', numberFilter);
 register('orderBy', orderByFilter);
 register('uppercase', uppercaseFilter);

}

/**

* @ngdoc filter
* @name 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 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>
      Search: <input ng-model="searchText">
NamePhone
Template:Friend.name Template:Friend.phone

      Any: <input ng-model="search.$"> 
Name only <input ng-model="search.name">
Phone only <input ng-model="search.phone"å>
NamePhone
Template:Friend.name Template:Friend.phone
    </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 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>
        <input type="number" ng-model="amount"> 
default currency symbol ($): Template:Amount
custom currency identifier (USD$): Template:Amount
    </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 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>
        Enter number: <input ng-model='val'>
Default formatting: Template:Val
No fractions: Template:Val
Negative number: Template:-val
    </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 = [];
 var hasExponent = false;
 if (numStr.indexOf('e') !== -1) {
   var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
   if (match && match[2] == '-' && match[3] > fractionSize + 1) {
     numStr = '0';
   } else {
     formatedText = numStr;
     hasExponent = true;
   }
 }
 if (!hasExponent) {
   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 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/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 oclock"`).
*
* @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>
      Template:1288323623006:
          Template:1288323623006
Template:1288323623006: Template:1288323623006
Template:1288323623006: Template:'1288323623006'
</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+))?)?)?(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 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 Template: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.
*
*
* @example:
  <doc:example>
    <doc:source>
{{ {'name':'value'} | json }}
    </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 ng.filter:lowercase
* @function
* @description
* Converts string to lowercase.
* @see angular.lowercase
*/

var lowercaseFilter = valueFn(lowercase);


/**

* @ngdoc filter
* @name ng.filter:uppercase
* @function
* @description
* Converts string to uppercase.
* @see angular.uppercase
*/

var uppercaseFilter = valueFn(uppercase);

/**

* @ngdoc function
* @name 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 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>
        Limit Template:Numbers to: <input type="integer" ng-model="limit">

Output: Template:Numbers

    </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 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 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>
Sorting predicate = {{predicate}}; reverse = {{reverse}}

        [ <a href="" ng-click="predicate=">unsorted</a> ]
<a href="" ng-click="predicate = 'name'; reverse=false">Name</a> (<a href ng-click="predicate = '-name'; reverse=false">^</a>) <a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a> <a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a>
Template:Friend.name Template:Friend.phone Template:Friend.age
      </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);

}

/**

* @ngdoc directive
* @name ng.directive:a
* @restrict E
*
* @description
* 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 `ngClick` directive
* 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();
         return false; // Needed for opera
       }
     });
   }
 }

});

/**

* @ngdoc directive
* @name ng.directive:ngHref
* @restrict A
*
* @description
* Using Angular markup like Template: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 Template:Hash with actual URL, the
* link will be broken and will most likely return a 404 error.
* The `ngHref` directive solves this problem.
*
* The buggy way to write it:
*
 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
 * 
*
* The correct way to write it:
*
 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
 * 
*
* @element A
* @param {template} ngHref any string which can contain `{{}}` markup.
*
* @example
* This example uses `link` variable inside `href` attribute:
   <doc:example>
     <doc:source>
       <input ng-model="value" />
<a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)
<a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)
<a id="link-3" ng-href="/Template:'123'">link 3</a> (link, reload!)
<a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)
<a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)
<a id="link-6" ng-href="Template:Value">link</a> (link, change location) </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().location().url()).toEqual('/6');
       });
     </doc:scenario>
   </doc:example>
*/

/**

* @ngdoc directive
* @name ng.directive:ngSrc
* @restrict A
*
* @description
* Using Angular markup like `Template:Hash` in a `src` attribute doesn't
* work right: The browser will fetch from the URL with the literal
* text `Template:Hash` until Angular replaces the expression inside
* `Template:Hash`. The `ngSrc` directive solves this problem.
*
* The buggy way to write it:
*
 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
 * 
*
* The correct way to write it:
*
 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
 * 
*
* @element IMG
* @param {template} ngSrc any string which can contain `{{}}` markup.
*/

/**

* @ngdoc directive
* @name ng.directive:ngDisabled
* @restrict A
*
* @description
*
* The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
*
 * <div ng-init="scope = { isDisabled: false }">
 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
 * </div>
 * 
*
* 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 the `ngDisabled` directive.
*
* @example
   <doc:example>
     <doc:source>
       Click me to toggle: <input type="checkbox" ng-model="checked">
<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 {expression} ngDisabled Angular expression that will be evaluated. */


/**

* @ngdoc directive
* @name ng.directive:ngChecked
* @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 the `ngChecked` directive.
* @example
   <doc:example>
     <doc:source>
       Check me to check both: <input type="checkbox" ng-model="master">
<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 {expression} ngChecked Angular expression that will be evaluated. */


/**

* @ngdoc directive
* @name ng.directive:ngMultiple
* @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 the `ngMultiple` directive.
*
* @example
    <doc:example>
      <doc:source>
        Check me check multiple: <input type="checkbox" ng-model="checked">
<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 {expression} ngMultiple Angular expression that will be evaluated. */


/**

* @ngdoc directive
* @name ng.directive:ngReadonly
* @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 the `ngReadonly` directive.
* @example
   <doc:example>
     <doc:source>
       Check me to make text readonly: <input type="checkbox" ng-model="checked">
<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 ng.directive:ngSelected
* @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 introduced the `ngSelected` directive.
* @example
   <doc:example>
     <doc:source>
       Check me to select: <input type="checkbox" ng-model="selected">
<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() {
       return function(scope, element, attr) {
         scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(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
     link: function(scope, element, attr) {
       attr.$observe(normalized, function(value) {
         if (!value)
            return;
         attr.$set(attrName, value);
         // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
         // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
         // to set the property as well to achieve the desired effect
         if (msie) element.prop(attrName, value);
       });
     }
   };
 };

});

var nullFormCtrl = {

 $addControl: noop,
 $removeControl: noop,
 $setValidity: noop,
 $setDirty: noop

};

/**

* @ngdoc object
* @name ng.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 ng.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;
   parentForm.$setDirty();
 };

}


/**

* @ngdoc directive
* @name ng.directive:ngForm
* @restrict EAC
*
* @description
* Nestable alias of {@link ng.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=} ngForm|name Name of the form. If specified, the form controller will be published into
*                       related scope, under this name.
*
*/
/**
* @ngdoc directive
* @name ng.directive:form
* @restrict E
*
* @description
* Directive that instantiates
* {@link ng.directive:form.FormController FormController}.
*
* If `name` attribute is specified, the form controller is published onto the current scope under
* this name.
*
* # Alias: {@link ng.directive:ngForm `ngForm`}
*
* 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 ng.directive:ngForm `ngForm`} 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:
*
* - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
* - {@link ng.directive:ngClick ngClick} directive on the first
 *  button or input field of type submit (input[type=submit])
*
* To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. 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
* (`ngSubmit`)
* - 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] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
*
* @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>
        Required!
userType = Template:UserType
myForm.input.$valid = Template:MyForm.input.$valid
myForm.input.$error = Template:MyForm.input.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.REQUIRED = Template:!!myForm.$error.REQUIRED
</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 formDirectiveFactory = function(isNgForm) {

 return ['$timeout', function($timeout) {
   var formDirective = {
     name: 'form',
     restrict: 'E',
     controller: FormController,
     compile: function() {
       return {
         pre: function(scope, formElement, attr, controller) {
           if (!attr.action) {
             // we can't use jq events because if a form is destroyed during submission the default
             // action is not prevented. see #1238
             //
             // IE 9 is not affected because it doesn't fire a submit event and try to do a full
             // page reload if the form was destroyed by submission of the form via a click handler
             // on a button in the form. Looks like an IE9 specific bug.
             var preventDefaultListener = function(event) {
               event.preventDefault
                 ? event.preventDefault()
                 : event.returnValue = false; // IE
             };
             addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
             // unregister the preventDefault listener so that we don't not leak memory but in a
             // way that will achieve the prevention of the default action.
             formElement.bind('$destroy', function() {
               $timeout(function() {
                 removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
               }, 0, false);
             });
           }
           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
             });
           }
         }
       };
     }
   };
   return isNgForm ? extend(copy(formDirective), {restrict: 'EAC'}) : formDirective;
 }];

};

var formDirective = formDirectiveFactory(); var ngFormDirective = formDirectiveFactory(true);

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 ng.directive:input.text
  *
  * @description
  * Standard HTML text input with angular data binding.
  *
  * @param {string} ngModel Assignable angular expression to data-bind to.
  * @param {string=} name Property name of the form under which the control is published.
  * @param {string=} required Adds `required` validation error key if the value is not entered.
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  *    `required` when you want to data-bind to the `required` attribute.
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  *    minlength.
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  *    maxlength.
  * @param {string=} ngPattern 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=} ngChange 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>
          
            Required!
          
            Single word only!
          text = Template:Text
myForm.input.$valid = Template:MyForm.input.$valid
myForm.input.$error = Template:MyForm.input.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
</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 ng.directive:input.number
  *
  * @description
  * Text input with number validation and transformation. Sets the `number` validation
  * error if not a valid number.
  *
  * @param {string} ngModel 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 {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  *    `required` when you want to data-bind to the `required` attribute.
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  *    minlength.
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  *    maxlength.
  * @param {string=} ngPattern 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=} ngChange 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>
          
            Required!
          
            Not valid number!
          value = Template:Value
myForm.input.$valid = Template:MyForm.input.$valid
myForm.input.$error = Template:MyForm.input.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
</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 ng.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} ngModel 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 {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  *    `required` when you want to data-bind to the `required` attribute.
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  *    minlength.
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  *    maxlength.
  * @param {string=} ngPattern 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=} ngChange 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>
          
            Required!
          
            Not valid url!
          text = Template:Text
myForm.input.$valid = Template:MyForm.input.$valid
myForm.input.$error = Template:MyForm.input.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
myForm.$error.url = Template:!!myForm.$error.url
</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 ng.directive:input.email
  *
  * @description
  * Text input with email validation. Sets the `email` validation error key if not a valid email
  * address.
  *
  * @param {string} ngModel 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 {string=} ngRequired Adds `required` attribute and `required` validation constraint to
  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
  *    `required` when you want to data-bind to the `required` attribute.
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
  *    minlength.
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
  *    maxlength.
  * @param {string=} ngPattern 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>
            
              Required!
            
              Not valid email!
            text = Template:Text
myForm.input.$valid = Template:MyForm.input.$valid
myForm.input.$error = Template:MyForm.input.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
myForm.$error.email = Template:!!myForm.$error.email
</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 ng.directive:input.radio
  *
  * @description
  * HTML radio button.
  *
  * @param {string} ngModel 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=} ngChange 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 
<input type="radio" ng-model="color" value="green"> Green
<input type="radio" ng-model="color" value="blue"> Blue
color = Template:Color
</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 ng.directive:input.checkbox
  *
  * @description
  * HTML checkbox.
  *
  * @param {string} ngModel Assignable angular expression to data-bind to.
  * @param {string=} name Property name of the form under which the control is published.
  * @param {string=} ngTrueValue The value to which the expression should be set when selected.
  * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
  * @param {string=} ngChange 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"> 
Value2: <input type="checkbox" ng-model="value2" ng-true-value="YES" ng-false-value="NO">
value1 = Template:Value1
value2 = Template:Value2
</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 - except on IE9 which doesn't fire the
 // input event on backspace, delete or cut
 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) {

 // make the name unique, if not defined
 if (isUndefined(attr.name)) {
   element.attr('name', nextUid());
 }
 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 ng.directive:textarea
* @restrict E
*
* @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 ng.directive:input input element}.
*
* @param {string} ngModel 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 {string=} ngRequired Adds `required` attribute and `required` validation constraint to
*    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
*    `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
*    minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
*    maxlength.
* @param {string=} ngPattern 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=} ngChange Angular expression to be executed when input changes due to user
*    interaction with the input element.
*/


/**

* @ngdoc directive
* @name ng.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} ngModel 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 {boolean=} ngRequired Sets `required` attribute if set to true
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
*    minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
*    maxlength.
* @param {string=} ngPattern 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=} ngChange 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>
        <form name="myForm">
          User name: <input type="text" name="userName" ng-model="user.name" required>
          
            Required!
Last name: <input type="text" name="lastName" ng-model="user.last" ng-minlength="3" ng-maxlength="10"> Too short! Too long!
</form>

        user = Template:User
myForm.userName.$valid = Template:MyForm.userName.$valid
myForm.userName.$error = Template:MyForm.userName.$error
myForm.lastName.$valid = Template:MyForm.lastName.$valid
myForm.userName.$error = Template:MyForm.lastName.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
myForm.$error.minlength = Template:!!myForm.$error.minlength
myForm.$error.maxlength = Template:!!myForm.$error.maxlength
     </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 ng.directive:ngModel.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
*
* `NgModelController` provides API for the `ng-model` directive. The controller contains
* services for data-binding, validation, CSS update, value formatting and parsing. It
* specifically does not contain any logic which deals with DOM rendering or listening to
* DOM events. The `NgModelController` is meant to be extended by other directives where, the
* directive provides DOM manipulation and the `NgModelController` provides the data-binding.
*
* This example shows how to use `NgModelController` with a custom control to achieve
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
* collaborate together to achieve the desired result.
*
* <example module="customControl">
   <file name="style.css">
     [contenteditable] {
       border: 1px solid black;
       background-color: white;
       min-height: 20px;
     }
     .ng-invalid {
       border: 1px solid red;
     }
   </file>
   <file name="script.js">
     angular.module('customControl', []).
       directive('contenteditable', function() {
         return {
           restrict: 'A', // only activate on element attribute
           require: '?ngModel', // get a hold of NgModelController
           link: function(scope, element, attrs, ngModel) {
             if(!ngModel) return; // do nothing if no ng-model
             // Specify how UI should be updated
             ngModel.$render = function() {
               element.html(ngModel.$viewValue || );
             };
             // Listen for change events to enable binding
             element.bind('blur keyup change', function() {
               scope.$apply(read);
             });
             read(); // initialize
             // Write data to the model
             function read() {
               ngModel.$setViewValue(element.html());
             }
           }
         };
       });
   </file>
   <file name="index.html">
     <form name="myForm">
Change me!
       Required!

      <textarea ng-model="userContent"></textarea>
     </form>
   </file>
   <file name="scenario.js">
     it('should data-bind and become invalid', function() {
       var contentEditable = element('[contenteditable]');
       expect(contentEditable.text()).toEqual('Change me!');
       input('userContent').enter();
       expect(contentEditable.text()).toEqual();
       expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
     });
   </file>
* </example>
*
*/

var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',

   function($scope, $exceptionHandler, $attr, $element, $parse) {
 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.$name = $attr.name;
 var ngModelGet = $parse($attr.ngModel),
     ngModelSet = ngModelGet.assign;
 if (!ngModelSet) {
   throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + $attr.ngModel +
       ' (' + startingTag($element) + ')');
 }
 /**
  * @ngdoc function
  * @name ng.directive:ngModel.NgModelController#$render
  * @methodOf ng.directive:ngModel.NgModelController
  *
  * @description
  * Called when the view needs to be updated. It is expected that the user of the ng-model
  * directive will implement this method.
  */
 this.$render = noop;
 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 ng.directive:ngModel.NgModelController#$setValidity
  * @methodOf ng.directive:ngModel.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  `Template: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 ng.directive:ngModel.NgModelController#$setViewValue
  * @methodOf ng.directive:ngModel.NgModelController
  *
  * @description
  * Read a value from view.
  *
  * This method should be called from within a DOM event handler.
  * For example {@link ng.directive:input input} or
  * {@link ng.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;
     ngModelSet($scope, value);
     forEach(this.$viewChangeListeners, function(listener) {
       try {
         listener();
       } catch(e) {
         $exceptionHandler(e);
       }
     })
   }
 };
 // model -> value
 var ctrl = this;
 $scope.$watch(function ngModelWatch() {
   var value = ngModelGet($scope);
   // if scope model value and ngModel value are out of sync
   if (ctrl.$modelValue !== value) {
     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 ng.directive:ngModel
*
* @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 `ngModel` as well.
*
* `ngModel` 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 ng.directive:form form}.
*
* For basic examples, how to use `ngModel`, see:
*
*  - {@link ng.directive:input input}
*    - {@link ng.directive:input.text text}
*    - {@link ng.directive:input.checkbox checkbox}
*    - {@link ng.directive:input.radio radio}
*    - {@link ng.directive:input.number number}
*    - {@link ng.directive:input.email email}
*    - {@link ng.directive:input.url url}
*  - {@link ng.directive:select select}
*  - {@link ng.directive:textarea textarea}
*
*/

var ngModelDirective = function() {

 return {
   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 ng.directive:ngChange
* @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 `ngModel` to be present.
*
* @element input
*
* @example
* <doc:example>
*   <doc:source>
*     <script>
*       function Controller($scope) {
*         $scope.counter = 0;
*         $scope.change = function() {
*           $scope.counter++;
*         };
*       }
*     </script>
*
*       <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>
* debug = Template:Confirmed
* counter = Template:Counter
*
*   </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;
     attr.required = true; // force truthy in case we are on non input element
     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 ng.directive:ngList
*
* @description
* Text input that converts between comma-separated string into an array of strings.
*
* @element input
* @param {string=} ngList 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>
        
          Required!
        names = Template:Names
myForm.namesInput.$valid = Template:MyForm.namesInput.$valid
myForm.namesInput.$error = Template:MyForm.namesInput.$error
myForm.$valid = Template:MyForm.$valid
myForm.$error.required = Template:!!myForm.$error.required
</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)) {
         return value.join(', ');
       }
       return undefined;
     });
   }
 };

};


var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;

var ngValueDirective = function() {

 return {
   priority: 100,
   compile: function(tpl, tplAttr) {
     if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
       return function(scope, elm, attr) {
         attr.$set('value', scope.$eval(attr.ngValue));
       };
     } else {
       return function(scope, elm, attr) {
         scope.$watch(attr.ngValue, function valueWatchAction(value) {
           attr.$set('value', value, false);
         });
       };
     }
   }
 };

};

/**

* @ngdoc directive
* @name ng.directive:ngBind
*
* @description
* The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
* with the value of a given expression, and to update the text content when the value of that
* expression changes.
*
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
* `Template:Expression` which is similar but less verbose.
*
* Once scenario in which the use of `ngBind` is prefered over `Template:Expression` binding is when
* it's desirable to put bindings into template that is momentarily displayed by the browser in its
* raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
* bindings invisible to the user while the page is loading.
*
* An alternative solution to this problem would be using the
* {@link ng.directive:ngCloak ngCloak} directive.
*
*
* @element ANY
* @param {expression} ngBind {@link guide/expression 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>
        Enter name: <input type="text" ng-model="name">
Hello !
    </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 ngBindWatchAction(value) {
   element.text(value == undefined ?  : value);
 });

});


/**

* @ngdoc directive
* @name ng.directive:ngBindTemplate
*
* @description
* The `ngBindTemplate` directive specifies that the element
* text should be replaced with the template in ngBindTemplate.
* Unlike ngBind the ngBindTemplate can contain multiple `Template:` ``
* 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} ngBindTemplate template of form
*   {{ expression }} 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>
       Salutation: <input type="text" ng-model="salutation">
Name: <input type="text" ng-model="name">

       
    </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);
   });
 }

}];


/**

* @ngdoc directive
* @name ng.directive:ngBindHtmlUnsafe
*
* @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 ngSanitize.directive:ngBindHtml ngBindHtml} directive is too
* restrictive and when you absolutely trust the source of the content you are binding to.
*
* See {@link ngSanitize.$sanitize $sanitize} docs for examples.
*
* @element ANY
* @param {expression} ngBindHtmlUnsafe {@link guide/expression Expression} to evaluate.
*/

var ngBindHtmlUnsafeDirective = [function() {

 return function(scope, element, attr) {
   element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
   scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
     element.html(value || );
   });
 };

}];

function classDirective(name, selector) {

 name = 'ngClass' + name;
 return ngDirective(function(scope, element, attr) {
   scope.$watch(attr[name], ngClassWatchAction, true);
   attr.$observe('class', function(value) {
     var ngClass = scope.$eval(attr[name]);
     ngClassWatchAction(ngClass, ngClass);
   });


   if (name !== 'ngClass') {
     scope.$watch('$index', function($index, old$index) {
       var mod = $index % 2;
       if (mod !== old$index % 2) {
         if (mod == selector) {
           addClass(scope.$eval(attr[name]));
         } else {
           removeClass(scope.$eval(attr[name]));
         }
       }
     });
   }


   function ngClassWatchAction(newVal, oldVal) {
     if (selector === true || scope.$index % 2 === selector) {
       if (oldVal && (newVal !== oldVal)) {
         removeClass(oldVal);
       }
       addClass(newVal);
     }
   }


   function removeClass(classVal) {
     if (isObject(classVal) && !isArray(classVal)) {
       classVal = map(classVal, function(v, k) { if (v) return k });
     }
     element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
   }


   function addClass(classVal) {
     if (isObject(classVal) && !isArray(classVal)) {
       classVal = map(classVal, function(v, k) { if (v) return k });
     }
     if (classVal) {
       element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
     }
   }
 });

}

/**

* @ngdoc directive
* @name ng.directive:ngClass
*
* @description
* The `ngClass` 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} ngClass {@link guide/expression 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
  <example>
    <file name="index.html">
     <input type="button" value="set" ng-click="myVar='my-class'">
     <input type="button" value="clear" ng-click="myVar=">
     
Sample Text </file> <file name="style.css"> .my-class { color: red; } </file> <file name="scenario.js"> it('should check ng-class', function() { expect(element('.doc-example-live span').prop('className')).not(). toMatch(/my-class/);
        using('.doc-example-live').element(':button:first').click();
        expect(element('.doc-example-live span').prop('className')).
          toMatch(/my-class/);
        using('.doc-example-live').element(':button:last').click();
        expect(element('.doc-example-live span').prop('className')).not().
          toMatch(/my-class/);
      });
    </file>
  </example>
*/

var ngClassDirective = classDirective(, true);

/**

* @ngdoc directive
* @name ng.directive:ngClassOdd
*
* @description
* The `ngClassOdd` and `ngClassEven` directives work exactly as
* {@link ng.directive:ngClass ngClass}, except it works in
* conjunction with `ngRepeat` and takes affect only on odd (even) rows.
*
* This directive can be applied only within a scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
* @element ANY
* @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
*   of the evaluation can be a string representing space delimited class names or an array.
*
* @example
  <example>
    <file name="index.html">
  1. Template:Name
    </file>
    <file name="style.css">
      .odd {
        color: red;
      }
      .even {
        color: blue;
      }
    </file>
    <file name="scenario.js">
      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/);
      });
    </file>
  </example>
*/

var ngClassOddDirective = classDirective('Odd', 0);

/**

* @ngdoc directive
* @name ng.directive:ngClassEven
*
* @description
* The `ngClassOdd` and `ngClassEven` works exactly as
* {@link ng.directive:ngClass ngClass}, except it works in
* conjunction with `ngRepeat` and takes affect only on odd (even) rows.
*
* This directive can be applied only within a scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
* @element ANY
* @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
*   result of the evaluation can be a string representing space delimited class names or an array.
*
* @example
  <example>
    <file name="index.html">
  1. Template:Name      
    </file>
    <file name="style.css">
      .odd {
        color: red;
      }
      .even {
        color: blue;
      }
    </file>
    <file name="scenario.js">
      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/);
      });
    </file>
  </example>
*/

var ngClassEvenDirective = classDirective('Even', 1);

/**

* @ngdoc directive
* @name ng.directive:ngCloak
*
* @description
* The `ngCloak` directive is used to prevent the Angular html template from being briefly
* displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
* directive to avoid the undesirable flicker effect caused by the html template display.
*
* The directive can be applied to the `<body>` element, but typically a fine-grained application is
* prefered in order to benefit from progressive rendering of the browser view.
*
* `ngCloak` works in cooperation with a css rule that is embedded within `angular.js` and
*  `angular.min.js` files. Following is the css rule:
*
*
 * [ng\:cloak], [ng-cloak], .ng-cloak {
 *   display: none;
 * }
 * 
*
* When this css rule is loaded by the browser, all html elements (including their children) that
* are tagged with the `ng-cloak` directive are hidden. When Angular comes across this directive
* during the compilation of the template it deletes the `ngCloak` element attribute, which
* makes the compiled element visible.
*
* 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 `ngCloak` in addition to `ngCloak` directive as shown in the example below.
*
* @element ANY
*
* @example
  <doc:example>
    <doc:source>
    </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 ng.directive:ngController
*
* @description
* The `ngController` 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 `ngController` 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 ng.$route}`
* service.
*
* @element ANY
* @scope
* @param {expression} ngController Name of a globally accessible constructor function or an
*     {@link guide/expression 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>
       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>
       Name: <input type="text" ng-model="name"/>
       [ <a href="" ng-click="greet()">greet</a> ]
Contact:
  • <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> ]
  • [ <a href="" ng-click="addContact()">add</a> ]
    </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 ng.directive:ngCsp
* @priority 1000
*
* @description
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
* This directive should be used on the root element of the application (typically the ``
 * element or other element with the {@link ng.directive:ngApp ngApp}
 * directive).
 *
 * If enabled the performance of template expression evaluator will suffer slightly, so don't enable
 * this mode unless you need it.
 *
 * @element html
 */

var ngCspDirective = ['$sniffer', function($sniffer) {
  return {
    priority: 1000,
    compile: function() {
      $sniffer.csp = true;
    }
  };
}];

/**
 * @ngdoc directive
 * @name ng.directive:ngClick
 *
 * @description
 * The ngClick allows you to specify custom behavior when
 * element is clicked.
 *
 * @element ANY
 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
 * click. (Event object is available as `$event`)
 *
 * @example
   
     
      
      count: {{count}}
     
     
       it('should check ng-click', function() {
         expect(binding('count')).toBe('0');
         element('.doc-example-live :button').click();
         expect(binding('count')).toBe('1');
       });
     
   
 */
/*
 * 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 ng.directive:ngDblclick
 *
 * @description
 * The `ngDblclick` directive allows you to specify custom behavior on dblclick event.
 *
 * @element ANY
 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
 * dblclick. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngMousedown
 *
 * @description
 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
 *
 * @element ANY
 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
 * mousedown. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngMouseup
 *
 * @description
 * Specify custom behavior on mouseup event.
 *
 * @element ANY
 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
 * mouseup. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */

/**
 * @ngdoc directive
 * @name ng.directive:ngMouseover
 *
 * @description
 * Specify custom behavior on mouseover event.
 *
 * @element ANY
 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
 * mouseover. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngMouseenter
 *
 * @description
 * Specify custom behavior on mouseenter event.
 *
 * @element ANY
 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
 * mouseenter. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngMouseleave
 *
 * @description
 * Specify custom behavior on mouseleave event.
 *
 * @element ANY
 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
 * mouseleave. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngMousemove
 *
 * @description
 * Specify custom behavior on mousemove event.
 *
 * @element ANY
 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
 * mousemove. (Event object is available as `$event`)
 *
 * @example
 * See {@link ng.directive:ngClick ngClick}
 */


/**
 * @ngdoc directive
 * @name ng.directive:ngSubmit
 *
 * @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} ngSubmit {@link guide/expression Expression} to eval.
 *
 * @example
   
     
      
      
Enter text and hit enter:
list={{list}}
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"]'); });
*/ var ngSubmitDirective = ngDirective(function(scope, element, attrs) { element.bind('submit', function() { scope.$apply(attrs.ngSubmit); }); }); /** * @ngdoc directive * @name ng.directive:ngInclude * @restrict ECA * * @description * Fetches, compiles and includes an external HTML fragment. * * Keep in mind that Same Origin Policy applies to included resources * (e.g. ngInclude won't work for cross-domain requests on all browsers and for * file:// access on some browsers). * * @scope * * @param {string} ngInclude|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 `ngInclude` should call {@link 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
url of the template: {{template.url}}
function Ctrl($scope) { $scope.templates = [ { name: 'template1.html', url: 'template1.html'} , { name: 'template2.html', url: 'template2.html'} ]; $scope.template = $scope.templates[0]; } Content of template1.html Content of template2.html it('should load template1.html', function() { expect(element('.doc-example-live [ng-include]').text()). toMatch(/Content of template1.html/); }); it('should load template2.html', function() { select('template').option('1'); expect(element('.doc-example-live [ng-include]').text()). toMatch(/Content of template2.html/); }); it('should change to blank', function() { select('template').option(''); expect(element('.doc-example-live [ng-include]').text()).toEqual(''); });
*/ /** * @ngdoc event * @name ng.directive:ngInclude#$includeContentLoaded * @eventOf ng.directive:ngInclude * @eventType emit on the current ngInclude scope * @description * Emitted every time the ngInclude 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) { var changeCounter = 0, childScope; var clearContent = function() { if (childScope) { childScope.$destroy(); childScope = null; } element.html(''); }; scope.$watch(srcExp, function ngIncludeWatchAction(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 ng.directive:ngInit * * @description * The `ngInit` directive specifies initialization tasks to be executed * before the template enters execution mode during bootstrap. * * @element ANY * @param {expression} ngInit {@link guide/expression Expression} to eval. * * @example
{{greeting}} {{person}}!
it('should check greeting', function() { expect(binding('greeting')).toBe('Hello'); expect(binding('person')).toBe('World'); });
*/ var ngInitDirective = ngDirective({ compile: function() { return { pre: function(scope, element, attrs) { scope.$eval(attrs.ngInit); } } } }); /** * @ngdoc directive * @name ng.directive:ngNonBindable * @priority 1000 * * @description * Sometimes it is necessary to write code which looks like bindings but which should be left alone * by angular. Use `ngNonBindable` 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 `ngNonBindable` is left alone. * * @example
Normal: {{1 + 2}}
Ignored: {{1 + 2}}
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/); });
*/ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 }); /** * @ngdoc directive * @name ng.directive:ngPluralize * @restrict EA * * @description * # Overview * `ngPluralize` 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/i18n Angular i18n} dev guide). You configure ngPluralize directive * 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 ngPluralize * You configure ngPluralize 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/expression * Angular expression}; these are evaluated on the current scope for its bound 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 ngPluralize: * *
 * 
 * 
 *
* * 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 * `{{personCount}}`. The closed braces `{}` is a placeholder * for {{numberExpression}}. * * # Configuring ngPluralize 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: * *
 * 
 * 
 * 
* * 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
Person 1:
Person 2:
Number of People:
Without Offset:
With Offset(2):
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.'); });
*/ 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 = {}, startSymbol = $interpolate.startSymbol(), endSymbol = $interpolate.endSymbol(); forEach(whens, function(expression, key) { whensExpFns[key] = $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' + offset + endSymbol)); }); scope.$watch(function ngPluralizeWatch() { 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 ngPluralizeWatchAction(newVal) { element.text(newVal); }); } }; }]; /** * @ngdoc directive * @name ng.directive:ngRepeat * * @description * The `ngRepeat` directive instantiates a template once per item from a collection. Each template * instance gets its own scope, where the given loop variable is set to the current collection item, * and `$index` is set to the item index or key. * * Special properties are exposed on the local scope of each template instance, including: * * * `$index` – `{number}` – iterator offset of the repeated element (0..length-1) * * `$first` – `{boolean}` – true if the repeated element is first in the iterator. * * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator. * * `$last` – `{boolean}` – true if the repeated element is last in the iterator. * * * @element ANY * @scope * @priority 1000 * @param {repeat_expression} ngRepeat 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 `ngRepeat` to display every person:
I have {{friends.length}} friends. They are:
  • [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
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"]); });
*/ 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 ngRepeat 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 ngRepeatWatch(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.$first = (index === 0); childScope.$last = (index === (collectionLength - 1)); childScope.$middle = !(childScope.$first || childScope.$last); 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 ng.directive:ngShow * * @description * The `ngShow` and `ngHide` directives show or hide a portion of the DOM tree (HTML) * conditionally. * * @element ANY * @param {expression} ngShow If the {@link guide/expression expression} is truthy * then the element is shown or hidden respectively. * * @example Click me:
Show: I show up when your checkbox is checked.
Hide: I hide when your checkbox is checked.
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); });
*/ //TODO(misko): refactor to remove element from the DOM var ngShowDirective = ngDirective(function(scope, element, attr){ scope.$watch(attr.ngShow, function ngShowWatchAction(value){ element.css('display', toBoolean(value) ? '' : 'none'); }); }); /** * @ngdoc directive * @name ng.directive:ngHide * * @description * The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML) * conditionally. * * @element ANY * @param {expression} ngHide If the {@link guide/expression expression} is truthy then * the element is shown or hidden respectively. * * @example Click me:
Show: I show up when you checkbox is checked?
Hide: I hide when you checkbox is checked?
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); });
*/ //TODO(misko): refactor to remove element from the DOM var ngHideDirective = ngDirective(function(scope, element, attr){ scope.$watch(attr.ngHide, function ngHideWatchAction(value){ element.css('display', toBoolean(value) ? 'none' : ''); }); }); /** * @ngdoc directive * @name ng.directive:ngStyle * * @description * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally. * * @element ANY * @param {expression} ngStyle {@link guide/expression Expression} which evals to an * object whose keys are CSS style names and values are corresponding values for those CSS * keys. * * @example
Sample Text
myStyle={{myStyle}}
span { color: black; } 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)'); });
*/ var ngStyleDirective = ngDirective(function(scope, element, attr) { scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) { if (oldStyles && (newStyles !== oldStyles)) { forEach(oldStyles, function(val, style) { element.css(style, '');}); } if (newStyles) element.css(newStyles); }, true); }); /** * @ngdoc directive * @name ng.directive:ngSwitch * @restrict EA * * @description * Conditionally change the DOM structure. * * @usageContent * ... * ... * ... * ... * * @scope * @param {*} ngSwitch|on expression to match against ng-switch-when. * @paramDescription * On child elments add: * * * `ngSwitchWhen`: the case statement to match against. If match then this * case will be displayed. * * `ngSwitchDefault`: the default case when no other casses match. * * @example
selection={{selection}}
Settings Div
Home Span default
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/); });
*/ 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 ngSwitchWatchAction(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 ng.directive:ngTransclude * * @description * Insert the transcluded DOM here. * * @element ANY * * @example


{{text}}
it('should have transcluded', function() { input('title').enter('TITLE'); input('text').enter('TEXT'); expect(binding('title')).toEqual('TITLE'); expect(binding('text')).toEqual('TEXT'); });
* */ var ngTranscludeDirective = ngDirective({ controller: ['$transclude', '$element', function($transclude, $element) { $transclude(function(clone) { $element.append(clone); }); }] }); /** * @ngdoc directive * @name ng.directive:ngView * @restrict ECA * * @description * # Overview * `ngView` is a directive that complements the {@link 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
Choose: Moby | Moby: Ch1 | Gatsby | Gatsby: Ch4 | Scarlet Letter

$location.path() = {{$location.path()}}
$route.current.template = {{$route.current.template}}
$route.current.params = {{$route.current.params}}
$route.current.scope.name = {{$route.current.scope.name}}
$routeParams = {{$routeParams}}
controller: {{name}}
Book Id: {{params.bookId}}
controller: {{name}}
Book Id: {{params.bookId}}
Chapter Id: {{params.chapterId}}
angular.module('ngView', [], function($routeProvider, $locationProvider) { $routeProvider.when('/Book/:bookId', { templateUrl: 'book.html', controller: BookCntl }); $routeProvider.when('/Book/:bookId/ch/:chapterId', { templateUrl: '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; } 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/); });
*/ /** * @ngdoc event * @name ng.directive:ngView#$viewContentLoaded * @eventOf ng.directive:ngView * @eventType emit on the current ngView scope * @description * Emitted every time the ngView 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 lastScope, onloadExp = attr.onload || ''; scope.$on('$routeChangeSuccess', update); update(); function destroyLastScope() { if (lastScope) { lastScope.$destroy(); lastScope = null; } } function clearContent() { element.html(''); destroyLastScope(); } function update() { var locals = $route.current && $route.current.locals, template = locals && locals.$template; if (template) { element.html(template); destroyLastScope(); var link = $compile(element.contents()), current = $route.current, controller; lastScope = current.scope = scope.$new(); if (current.controller) { locals.$scope = lastScope; controller = $controller(current.controller, locals); element.contents().data('$ngControllerController', controller); } link(lastScope); lastScope.$emit('$viewContentLoaded'); lastScope.$eval(onloadExp); // $anchorScroll might listen on event... $anchorScroll(); } else { clearContent(); } } } }; }]; /** * @ngdoc directive * @name ng.directive:script * * @description * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the * template can be used by `ngInclude`, `ngView` or directive templates. * * @restrict E * @param {'text/ng-template'} type must be set to `'text/ng-template'` * * @example Load inlined template
it('should load template defined inside script tag', function() { element('#tpl-link').click(); expect(element('#tpl-content').text()).toMatch(/Content of the template/); });
*/ var scriptDirective = ['$templateCache', function($templateCache) { return { restrict: 'E', terminal: true, compile: function(element, attr) { if (attr.type == 'text/ng-template') { var templateUrl = attr.id, // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent text = element[0].text; $templateCache.put(templateUrl, text); } } }; }]; /** * @ngdoc directive * @name ng.directive:select * @restrict E * * @description * HTML `SELECT` element with angular data-binding. * * # `ngOptions` * * Optionally `ngOptions` attribute can be used to dynamically generate a list of `
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'); }); */ 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+(.*)$/, nullModelCtrl = {$setViewValue: noop}; return { restrict: 'E', require: ['select', '?ngModel'], controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) { var self = this, optionsMap = {}, ngModelCtrl = nullModelCtrl, nullOption, unknownOption; self.databound = $attrs.ngModel; self.init = function(ngModelCtrl_, nullOption_, unknownOption_) { ngModelCtrl = ngModelCtrl_; nullOption = nullOption_; unknownOption = unknownOption_; } self.addOption = function(value) { optionsMap[value] = true; if (ngModelCtrl.$viewValue == value) { $element.val(value); if (unknownOption.parent()) unknownOption.remove(); } }; self.removeOption = function(value) { if (this.hasOption(value)) { delete optionsMap[value]; if (ngModelCtrl.$viewValue == value) { this.renderUnknownOption(value); } } }; self.renderUnknownOption = function(val) { var unknownVal = '? ' + hashKey(val) + ' ?'; unknownOption.val(unknownVal); $element.prepend(unknownOption); $element.val(unknownVal); unknownOption.prop('selected', true); // needed for IE } self.hasOption = function(value) { return optionsMap.hasOwnProperty(value); } $scope.$on('$destroy', function() { // disable unknown option so that we don't do work when the whole select is being destroyed self.renderUnknownOption = noop; }); }], link: function(scope, element, attr, ctrls) { // if ngModel is not defined, we don't need to do anything if (!ctrls[1]) return; var selectCtrl = ctrls[0], ngModelCtrl = ctrls[1], multiple = attr.multiple, optionsExp = attr.ngOptions, nullOption = false, // if false, user will not be able to select it (used by ngOptions) emptyOption, // we can't just jqLite('