Clean up to prepare new version of API
[src/app-framework-demo.git] / afm-client / bower_components / angular / angular.js
1 /**
2  * @license AngularJS v1.3.20
3  * (c) 2010-2014 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window, document, undefined) {'use strict';
7
8 /**
9  * @description
10  *
11  * This object provides a utility for producing rich Error messages within
12  * Angular. It can be called as follows:
13  *
14  * var exampleMinErr = minErr('example');
15  * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16  *
17  * The above creates an instance of minErr in the example namespace. The
18  * resulting error will have a namespaced error code of example.one.  The
19  * resulting error will replace {0} with the value of foo, and {1} with the
20  * value of bar. The object is not restricted in the number of arguments it can
21  * take.
22  *
23  * If fewer arguments are specified than necessary for interpolation, the extra
24  * interpolation markers will be preserved in the final string.
25  *
26  * Since data will be parsed statically during a build step, some restrictions
27  * are applied with respect to how minErr instances are created and called.
28  * Instances should have names of the form namespaceMinErr for a minErr created
29  * using minErr('namespace') . Error codes, namespaces and template strings
30  * should all be static strings, not variables or general expressions.
31  *
32  * @param {string} module The namespace to use for the new minErr instance.
33  * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
34  *   error from returned function, for cases when a particular type of error is useful.
35  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
36  */
37
38 function minErr(module, ErrorConstructor) {
39   ErrorConstructor = ErrorConstructor || Error;
40   return function() {
41     var code = arguments[0],
42       prefix = '[' + (module ? module + ':' : '') + code + '] ',
43       template = arguments[1],
44       templateArgs = arguments,
45
46       message, i;
47
48     message = prefix + template.replace(/\{\d+\}/g, function(match) {
49       var index = +match.slice(1, -1), arg;
50
51       if (index + 2 < templateArgs.length) {
52         return toDebugString(templateArgs[index + 2]);
53       }
54       return match;
55     });
56
57     message = message + '\nhttp://errors.angularjs.org/1.3.20/' +
58       (module ? module + '/' : '') + code;
59     for (i = 2; i < arguments.length; i++) {
60       message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
61         encodeURIComponent(toDebugString(arguments[i]));
62     }
63     return new ErrorConstructor(message);
64   };
65 }
66
67 /* We need to tell jshint what variables are being exported */
68 /* global angular: true,
69   msie: true,
70   jqLite: true,
71   jQuery: true,
72   slice: true,
73   splice: true,
74   push: true,
75   toString: true,
76   ngMinErr: true,
77   angularModule: true,
78   uid: true,
79   REGEX_STRING_REGEXP: true,
80   VALIDITY_STATE_PROPERTY: true,
81
82   lowercase: true,
83   uppercase: true,
84   manualLowercase: true,
85   manualUppercase: true,
86   nodeName_: true,
87   isArrayLike: true,
88   forEach: true,
89   sortedKeys: true,
90   forEachSorted: true,
91   reverseParams: true,
92   nextUid: true,
93   setHashKey: true,
94   extend: true,
95   int: true,
96   inherit: true,
97   noop: true,
98   identity: true,
99   valueFn: true,
100   isUndefined: true,
101   isDefined: true,
102   isObject: true,
103   isString: true,
104   isNumber: true,
105   isDate: true,
106   isArray: true,
107   isFunction: true,
108   isRegExp: true,
109   isWindow: true,
110   isScope: true,
111   isFile: true,
112   isFormData: true,
113   isBlob: true,
114   isBoolean: true,
115   isPromiseLike: true,
116   trim: true,
117   escapeForRegexp: true,
118   isElement: true,
119   makeMap: true,
120   includes: true,
121   arrayRemove: true,
122   copy: true,
123   shallowCopy: true,
124   equals: true,
125   csp: true,
126   concat: true,
127   sliceArgs: true,
128   bind: true,
129   toJsonReplacer: true,
130   toJson: true,
131   fromJson: true,
132   startingTag: true,
133   tryDecodeURIComponent: true,
134   parseKeyValue: true,
135   toKeyValue: true,
136   encodeUriSegment: true,
137   encodeUriQuery: true,
138   angularInit: true,
139   bootstrap: true,
140   getTestability: true,
141   snake_case: true,
142   bindJQuery: true,
143   assertArg: true,
144   assertArgFn: true,
145   assertNotHasOwnProperty: true,
146   getter: true,
147   getBlockNodes: true,
148   hasOwnProperty: true,
149   createMap: true,
150
151   NODE_TYPE_ELEMENT: true,
152   NODE_TYPE_ATTRIBUTE: true,
153   NODE_TYPE_TEXT: true,
154   NODE_TYPE_COMMENT: true,
155   NODE_TYPE_DOCUMENT: true,
156   NODE_TYPE_DOCUMENT_FRAGMENT: true,
157 */
158
159 ////////////////////////////////////
160
161 /**
162  * @ngdoc module
163  * @name ng
164  * @module ng
165  * @description
166  *
167  * # ng (core module)
168  * The ng module is loaded by default when an AngularJS application is started. The module itself
169  * contains the essential components for an AngularJS application to function. The table below
170  * lists a high level breakdown of each of the services/factories, filters, directives and testing
171  * components available within this core module.
172  *
173  * <div doc-module-components="ng"></div>
174  */
175
176 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
177
178 // The name of a form control's ValidityState property.
179 // This is used so that it's possible for internal tests to create mock ValidityStates.
180 var VALIDITY_STATE_PROPERTY = 'validity';
181
182 /**
183  * @ngdoc function
184  * @name angular.lowercase
185  * @module ng
186  * @kind function
187  *
188  * @description Converts the specified string to lowercase.
189  * @param {string} string String to be converted to lowercase.
190  * @returns {string} Lowercased string.
191  */
192 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
193 var hasOwnProperty = Object.prototype.hasOwnProperty;
194
195 /**
196  * @ngdoc function
197  * @name angular.uppercase
198  * @module ng
199  * @kind function
200  *
201  * @description Converts the specified string to uppercase.
202  * @param {string} string String to be converted to uppercase.
203  * @returns {string} Uppercased string.
204  */
205 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
206
207
208 var manualLowercase = function(s) {
209   /* jshint bitwise: false */
210   return isString(s)
211       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
212       : s;
213 };
214 var manualUppercase = function(s) {
215   /* jshint bitwise: false */
216   return isString(s)
217       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
218       : s;
219 };
220
221
222 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
223 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
224 // with correct but slower alternatives.
225 if ('i' !== 'I'.toLowerCase()) {
226   lowercase = manualLowercase;
227   uppercase = manualUppercase;
228 }
229
230
231 var
232     msie,             // holds major version number for IE, or NaN if UA is not IE.
233     jqLite,           // delay binding since jQuery could be loaded after us.
234     jQuery,           // delay binding
235     slice             = [].slice,
236     splice            = [].splice,
237     push              = [].push,
238     toString          = Object.prototype.toString,
239     ngMinErr          = minErr('ng'),
240
241     /** @name angular */
242     angular           = window.angular || (window.angular = {}),
243     angularModule,
244     uid               = 0;
245
246 /**
247  * documentMode is an IE-only property
248  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
249  */
250 msie = document.documentMode;
251
252
253 /**
254  * @private
255  * @param {*} obj
256  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
257  *                   String ...)
258  */
259 function isArrayLike(obj) {
260   if (obj == null || isWindow(obj)) {
261     return false;
262   }
263
264   // Support: iOS 8.2 (not reproducible in simulator)
265   // "length" in obj used to prevent JIT error (gh-11508)
266   var length = "length" in Object(obj) && obj.length;
267
268   if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
269     return true;
270   }
271
272   return isString(obj) || isArray(obj) || length === 0 ||
273          typeof length === 'number' && length > 0 && (length - 1) in obj;
274 }
275
276 /**
277  * @ngdoc function
278  * @name angular.forEach
279  * @module ng
280  * @kind function
281  *
282  * @description
283  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
284  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
285  * is the value of an object property or an array element, `key` is the object property key or
286  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
287  *
288  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
289  * using the `hasOwnProperty` method.
290  *
291  * Unlike ES262's
292  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
293  * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
294  * return the value provided.
295  *
296    ```js
297      var values = {name: 'misko', gender: 'male'};
298      var log = [];
299      angular.forEach(values, function(value, key) {
300        this.push(key + ': ' + value);
301      }, log);
302      expect(log).toEqual(['name: misko', 'gender: male']);
303    ```
304  *
305  * @param {Object|Array} obj Object to iterate over.
306  * @param {Function} iterator Iterator function.
307  * @param {Object=} context Object to become context (`this`) for the iterator function.
308  * @returns {Object|Array} Reference to `obj`.
309  */
310
311 function forEach(obj, iterator, context) {
312   var key, length;
313   if (obj) {
314     if (isFunction(obj)) {
315       for (key in obj) {
316         // Need to check if hasOwnProperty exists,
317         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
318         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
319           iterator.call(context, obj[key], key, obj);
320         }
321       }
322     } else if (isArray(obj) || isArrayLike(obj)) {
323       var isPrimitive = typeof obj !== 'object';
324       for (key = 0, length = obj.length; key < length; key++) {
325         if (isPrimitive || key in obj) {
326           iterator.call(context, obj[key], key, obj);
327         }
328       }
329     } else if (obj.forEach && obj.forEach !== forEach) {
330         obj.forEach(iterator, context, obj);
331     } else {
332       for (key in obj) {
333         if (obj.hasOwnProperty(key)) {
334           iterator.call(context, obj[key], key, obj);
335         }
336       }
337     }
338   }
339   return obj;
340 }
341
342 function sortedKeys(obj) {
343   return Object.keys(obj).sort();
344 }
345
346 function forEachSorted(obj, iterator, context) {
347   var keys = sortedKeys(obj);
348   for (var i = 0; i < keys.length; i++) {
349     iterator.call(context, obj[keys[i]], keys[i]);
350   }
351   return keys;
352 }
353
354
355 /**
356  * when using forEach the params are value, key, but it is often useful to have key, value.
357  * @param {function(string, *)} iteratorFn
358  * @returns {function(*, string)}
359  */
360 function reverseParams(iteratorFn) {
361   return function(value, key) { iteratorFn(key, value); };
362 }
363
364 /**
365  * A consistent way of creating unique IDs in angular.
366  *
367  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
368  * we hit number precision issues in JavaScript.
369  *
370  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
371  *
372  * @returns {number} an unique alpha-numeric string
373  */
374 function nextUid() {
375   return ++uid;
376 }
377
378
379 /**
380  * Set or clear the hashkey for an object.
381  * @param obj object
382  * @param h the hashkey (!truthy to delete the hashkey)
383  */
384 function setHashKey(obj, h) {
385   if (h) {
386     obj.$$hashKey = h;
387   } else {
388     delete obj.$$hashKey;
389   }
390 }
391
392 /**
393  * @ngdoc function
394  * @name angular.extend
395  * @module ng
396  * @kind function
397  *
398  * @description
399  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
400  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
401  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
402  * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
403  *
404  * @param {Object} dst Destination object.
405  * @param {...Object} src Source object(s).
406  * @returns {Object} Reference to `dst`.
407  */
408 function extend(dst) {
409   var h = dst.$$hashKey;
410
411   for (var i = 1, ii = arguments.length; i < ii; i++) {
412     var obj = arguments[i];
413     if (obj) {
414       var keys = Object.keys(obj);
415       for (var j = 0, jj = keys.length; j < jj; j++) {
416         var key = keys[j];
417         dst[key] = obj[key];
418       }
419     }
420   }
421
422   setHashKey(dst, h);
423   return dst;
424 }
425
426 function int(str) {
427   return parseInt(str, 10);
428 }
429
430
431 function inherit(parent, extra) {
432   return extend(Object.create(parent), extra);
433 }
434
435 /**
436  * @ngdoc function
437  * @name angular.noop
438  * @module ng
439  * @kind function
440  *
441  * @description
442  * A function that performs no operations. This function can be useful when writing code in the
443  * functional style.
444    ```js
445      function foo(callback) {
446        var result = calculateResult();
447        (callback || angular.noop)(result);
448      }
449    ```
450  */
451 function noop() {}
452 noop.$inject = [];
453
454
455 /**
456  * @ngdoc function
457  * @name angular.identity
458  * @module ng
459  * @kind function
460  *
461  * @description
462  * A function that returns its first argument. This function is useful when writing code in the
463  * functional style.
464  *
465    ```js
466      function transformer(transformationFn, value) {
467        return (transformationFn || angular.identity)(value);
468      };
469    ```
470   * @param {*} value to be returned.
471   * @returns {*} the value passed in.
472  */
473 function identity($) {return $;}
474 identity.$inject = [];
475
476
477 function valueFn(value) {return function() {return value;};}
478
479 /**
480  * @ngdoc function
481  * @name angular.isUndefined
482  * @module ng
483  * @kind function
484  *
485  * @description
486  * Determines if a reference is undefined.
487  *
488  * @param {*} value Reference to check.
489  * @returns {boolean} True if `value` is undefined.
490  */
491 function isUndefined(value) {return typeof value === 'undefined';}
492
493
494 /**
495  * @ngdoc function
496  * @name angular.isDefined
497  * @module ng
498  * @kind function
499  *
500  * @description
501  * Determines if a reference is defined.
502  *
503  * @param {*} value Reference to check.
504  * @returns {boolean} True if `value` is defined.
505  */
506 function isDefined(value) {return typeof value !== 'undefined';}
507
508
509 /**
510  * @ngdoc function
511  * @name angular.isObject
512  * @module ng
513  * @kind function
514  *
515  * @description
516  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
517  * considered to be objects. Note that JavaScript arrays are objects.
518  *
519  * @param {*} value Reference to check.
520  * @returns {boolean} True if `value` is an `Object` but not `null`.
521  */
522 function isObject(value) {
523   // http://jsperf.com/isobject4
524   return value !== null && typeof value === 'object';
525 }
526
527
528 /**
529  * @ngdoc function
530  * @name angular.isString
531  * @module ng
532  * @kind function
533  *
534  * @description
535  * Determines if a reference is a `String`.
536  *
537  * @param {*} value Reference to check.
538  * @returns {boolean} True if `value` is a `String`.
539  */
540 function isString(value) {return typeof value === 'string';}
541
542
543 /**
544  * @ngdoc function
545  * @name angular.isNumber
546  * @module ng
547  * @kind function
548  *
549  * @description
550  * Determines if a reference is a `Number`.
551  *
552  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
553  *
554  * If you wish to exclude these then you can use the native
555  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
556  * method.
557  *
558  * @param {*} value Reference to check.
559  * @returns {boolean} True if `value` is a `Number`.
560  */
561 function isNumber(value) {return typeof value === 'number';}
562
563
564 /**
565  * @ngdoc function
566  * @name angular.isDate
567  * @module ng
568  * @kind function
569  *
570  * @description
571  * Determines if a value is a date.
572  *
573  * @param {*} value Reference to check.
574  * @returns {boolean} True if `value` is a `Date`.
575  */
576 function isDate(value) {
577   return toString.call(value) === '[object Date]';
578 }
579
580
581 /**
582  * @ngdoc function
583  * @name angular.isArray
584  * @module ng
585  * @kind function
586  *
587  * @description
588  * Determines if a reference is an `Array`.
589  *
590  * @param {*} value Reference to check.
591  * @returns {boolean} True if `value` is an `Array`.
592  */
593 var isArray = Array.isArray;
594
595 /**
596  * @ngdoc function
597  * @name angular.isFunction
598  * @module ng
599  * @kind function
600  *
601  * @description
602  * Determines if a reference is a `Function`.
603  *
604  * @param {*} value Reference to check.
605  * @returns {boolean} True if `value` is a `Function`.
606  */
607 function isFunction(value) {return typeof value === 'function';}
608
609
610 /**
611  * Determines if a value is a regular expression object.
612  *
613  * @private
614  * @param {*} value Reference to check.
615  * @returns {boolean} True if `value` is a `RegExp`.
616  */
617 function isRegExp(value) {
618   return toString.call(value) === '[object RegExp]';
619 }
620
621
622 /**
623  * Checks if `obj` is a window object.
624  *
625  * @private
626  * @param {*} obj Object to check
627  * @returns {boolean} True if `obj` is a window obj.
628  */
629 function isWindow(obj) {
630   return obj && obj.window === obj;
631 }
632
633
634 function isScope(obj) {
635   return obj && obj.$evalAsync && obj.$watch;
636 }
637
638
639 function isFile(obj) {
640   return toString.call(obj) === '[object File]';
641 }
642
643
644 function isFormData(obj) {
645   return toString.call(obj) === '[object FormData]';
646 }
647
648
649 function isBlob(obj) {
650   return toString.call(obj) === '[object Blob]';
651 }
652
653
654 function isBoolean(value) {
655   return typeof value === 'boolean';
656 }
657
658
659 function isPromiseLike(obj) {
660   return obj && isFunction(obj.then);
661 }
662
663
664 var trim = function(value) {
665   return isString(value) ? value.trim() : value;
666 };
667
668 // Copied from:
669 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
670 // Prereq: s is a string.
671 var escapeForRegexp = function(s) {
672   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
673            replace(/\x08/g, '\\x08');
674 };
675
676
677 /**
678  * @ngdoc function
679  * @name angular.isElement
680  * @module ng
681  * @kind function
682  *
683  * @description
684  * Determines if a reference is a DOM element (or wrapped jQuery element).
685  *
686  * @param {*} value Reference to check.
687  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
688  */
689 function isElement(node) {
690   return !!(node &&
691     (node.nodeName  // we are a direct element
692     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
693 }
694
695 /**
696  * @param str 'key1,key2,...'
697  * @returns {object} in the form of {key1:true, key2:true, ...}
698  */
699 function makeMap(str) {
700   var obj = {}, items = str.split(","), i;
701   for (i = 0; i < items.length; i++)
702     obj[items[i]] = true;
703   return obj;
704 }
705
706
707 function nodeName_(element) {
708   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
709 }
710
711 function includes(array, obj) {
712   return Array.prototype.indexOf.call(array, obj) != -1;
713 }
714
715 function arrayRemove(array, value) {
716   var index = array.indexOf(value);
717   if (index >= 0)
718     array.splice(index, 1);
719   return value;
720 }
721
722 /**
723  * @ngdoc function
724  * @name angular.copy
725  * @module ng
726  * @kind function
727  *
728  * @description
729  * Creates a deep copy of `source`, which should be an object or an array.
730  *
731  * * If no destination is supplied, a copy of the object or array is created.
732  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
733  *   are deleted and then all elements/properties from the source are copied to it.
734  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
735  * * If `source` is identical to 'destination' an exception will be thrown.
736  *
737  * @param {*} source The source that will be used to make a copy.
738  *                   Can be any type, including primitives, `null`, and `undefined`.
739  * @param {(Object|Array)=} destination Destination into which the source is copied. If
740  *     provided, must be of the same type as `source`.
741  * @returns {*} The copy or updated `destination`, if `destination` was specified.
742  *
743  * @example
744  <example module="copyExample">
745  <file name="index.html">
746  <div ng-controller="ExampleController">
747  <form novalidate class="simple-form">
748  Name: <input type="text" ng-model="user.name" /><br />
749  E-mail: <input type="email" ng-model="user.email" /><br />
750  Gender: <input type="radio" ng-model="user.gender" value="male" />male
751  <input type="radio" ng-model="user.gender" value="female" />female<br />
752  <button ng-click="reset()">RESET</button>
753  <button ng-click="update(user)">SAVE</button>
754  </form>
755  <pre>form = {{user | json}}</pre>
756  <pre>master = {{master | json}}</pre>
757  </div>
758
759  <script>
760   angular.module('copyExample', [])
761     .controller('ExampleController', ['$scope', function($scope) {
762       $scope.master= {};
763
764       $scope.update = function(user) {
765         // Example with 1 argument
766         $scope.master= angular.copy(user);
767       };
768
769       $scope.reset = function() {
770         // Example with 2 arguments
771         angular.copy($scope.master, $scope.user);
772       };
773
774       $scope.reset();
775     }]);
776  </script>
777  </file>
778  </example>
779  */
780 function copy(source, destination, stackSource, stackDest) {
781   if (isWindow(source) || isScope(source)) {
782     throw ngMinErr('cpws',
783       "Can't copy! Making copies of Window or Scope instances is not supported.");
784   }
785
786   if (!destination) {
787     destination = source;
788     if (source) {
789       if (isArray(source)) {
790         destination = copy(source, [], stackSource, stackDest);
791       } else if (isDate(source)) {
792         destination = new Date(source.getTime());
793       } else if (isRegExp(source)) {
794         destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
795         destination.lastIndex = source.lastIndex;
796       } else if (isObject(source)) {
797         var emptyObject = Object.create(Object.getPrototypeOf(source));
798         destination = copy(source, emptyObject, stackSource, stackDest);
799       }
800     }
801   } else {
802     if (source === destination) throw ngMinErr('cpi',
803       "Can't copy! Source and destination are identical.");
804
805     stackSource = stackSource || [];
806     stackDest = stackDest || [];
807
808     if (isObject(source)) {
809       var index = stackSource.indexOf(source);
810       if (index !== -1) return stackDest[index];
811
812       stackSource.push(source);
813       stackDest.push(destination);
814     }
815
816     var result;
817     if (isArray(source)) {
818       destination.length = 0;
819       for (var i = 0; i < source.length; i++) {
820         result = copy(source[i], null, stackSource, stackDest);
821         if (isObject(source[i])) {
822           stackSource.push(source[i]);
823           stackDest.push(result);
824         }
825         destination.push(result);
826       }
827     } else {
828       var h = destination.$$hashKey;
829       if (isArray(destination)) {
830         destination.length = 0;
831       } else {
832         forEach(destination, function(value, key) {
833           delete destination[key];
834         });
835       }
836       for (var key in source) {
837         if (source.hasOwnProperty(key)) {
838           result = copy(source[key], null, stackSource, stackDest);
839           if (isObject(source[key])) {
840             stackSource.push(source[key]);
841             stackDest.push(result);
842           }
843           destination[key] = result;
844         }
845       }
846       setHashKey(destination,h);
847     }
848
849   }
850   return destination;
851 }
852
853 /**
854  * Creates a shallow copy of an object, an array or a primitive.
855  *
856  * Assumes that there are no proto properties for objects.
857  */
858 function shallowCopy(src, dst) {
859   if (isArray(src)) {
860     dst = dst || [];
861
862     for (var i = 0, ii = src.length; i < ii; i++) {
863       dst[i] = src[i];
864     }
865   } else if (isObject(src)) {
866     dst = dst || {};
867
868     for (var key in src) {
869       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
870         dst[key] = src[key];
871       }
872     }
873   }
874
875   return dst || src;
876 }
877
878
879 /**
880  * @ngdoc function
881  * @name angular.equals
882  * @module ng
883  * @kind function
884  *
885  * @description
886  * Determines if two objects or two values are equivalent. Supports value types, regular
887  * expressions, arrays and objects.
888  *
889  * Two objects or values are considered equivalent if at least one of the following is true:
890  *
891  * * Both objects or values pass `===` comparison.
892  * * Both objects or values are of the same type and all of their properties are equal by
893  *   comparing them with `angular.equals`.
894  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
895  * * Both values represent the same regular expression (In JavaScript,
896  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
897  *   representation matches).
898  *
899  * During a property comparison, properties of `function` type and properties with names
900  * that begin with `$` are ignored.
901  *
902  * Scope and DOMWindow objects are being compared only by identify (`===`).
903  *
904  * @param {*} o1 Object or value to compare.
905  * @param {*} o2 Object or value to compare.
906  * @returns {boolean} True if arguments are equal.
907  */
908 function equals(o1, o2) {
909   if (o1 === o2) return true;
910   if (o1 === null || o2 === null) return false;
911   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
912   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
913   if (t1 == t2) {
914     if (t1 == 'object') {
915       if (isArray(o1)) {
916         if (!isArray(o2)) return false;
917         if ((length = o1.length) == o2.length) {
918           for (key = 0; key < length; key++) {
919             if (!equals(o1[key], o2[key])) return false;
920           }
921           return true;
922         }
923       } else if (isDate(o1)) {
924         if (!isDate(o2)) return false;
925         return equals(o1.getTime(), o2.getTime());
926       } else if (isRegExp(o1)) {
927         return isRegExp(o2) ? o1.toString() == o2.toString() : false;
928       } else {
929         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
930           isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
931         keySet = {};
932         for (key in o1) {
933           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
934           if (!equals(o1[key], o2[key])) return false;
935           keySet[key] = true;
936         }
937         for (key in o2) {
938           if (!keySet.hasOwnProperty(key) &&
939               key.charAt(0) !== '$' &&
940               o2[key] !== undefined &&
941               !isFunction(o2[key])) return false;
942         }
943         return true;
944       }
945     }
946   }
947   return false;
948 }
949
950 var csp = function() {
951   if (isDefined(csp.isActive_)) return csp.isActive_;
952
953   var active = !!(document.querySelector('[ng-csp]') ||
954                   document.querySelector('[data-ng-csp]'));
955
956   if (!active) {
957     try {
958       /* jshint -W031, -W054 */
959       new Function('');
960       /* jshint +W031, +W054 */
961     } catch (e) {
962       active = true;
963     }
964   }
965
966   return (csp.isActive_ = active);
967 };
968
969
970
971 function concat(array1, array2, index) {
972   return array1.concat(slice.call(array2, index));
973 }
974
975 function sliceArgs(args, startIndex) {
976   return slice.call(args, startIndex || 0);
977 }
978
979
980 /* jshint -W101 */
981 /**
982  * @ngdoc function
983  * @name angular.bind
984  * @module ng
985  * @kind function
986  *
987  * @description
988  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
989  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
990  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
991  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
992  *
993  * @param {Object} self Context which `fn` should be evaluated in.
994  * @param {function()} fn Function to be bound.
995  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
996  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
997  */
998 /* jshint +W101 */
999 function bind(self, fn) {
1000   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1001   if (isFunction(fn) && !(fn instanceof RegExp)) {
1002     return curryArgs.length
1003       ? function() {
1004           return arguments.length
1005             ? fn.apply(self, concat(curryArgs, arguments, 0))
1006             : fn.apply(self, curryArgs);
1007         }
1008       : function() {
1009           return arguments.length
1010             ? fn.apply(self, arguments)
1011             : fn.call(self);
1012         };
1013   } else {
1014     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1015     return fn;
1016   }
1017 }
1018
1019
1020 function toJsonReplacer(key, value) {
1021   var val = value;
1022
1023   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1024     val = undefined;
1025   } else if (isWindow(value)) {
1026     val = '$WINDOW';
1027   } else if (value &&  document === value) {
1028     val = '$DOCUMENT';
1029   } else if (isScope(value)) {
1030     val = '$SCOPE';
1031   }
1032
1033   return val;
1034 }
1035
1036
1037 /**
1038  * @ngdoc function
1039  * @name angular.toJson
1040  * @module ng
1041  * @kind function
1042  *
1043  * @description
1044  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1045  * stripped since angular uses this notation internally.
1046  *
1047  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1048  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1049  *    If set to an integer, the JSON output will contain that many spaces per indentation.
1050  * @returns {string|undefined} JSON-ified string representing `obj`.
1051  */
1052 function toJson(obj, pretty) {
1053   if (typeof obj === 'undefined') return undefined;
1054   if (!isNumber(pretty)) {
1055     pretty = pretty ? 2 : null;
1056   }
1057   return JSON.stringify(obj, toJsonReplacer, pretty);
1058 }
1059
1060
1061 /**
1062  * @ngdoc function
1063  * @name angular.fromJson
1064  * @module ng
1065  * @kind function
1066  *
1067  * @description
1068  * Deserializes a JSON string.
1069  *
1070  * @param {string} json JSON string to deserialize.
1071  * @returns {Object|Array|string|number} Deserialized JSON string.
1072  */
1073 function fromJson(json) {
1074   return isString(json)
1075       ? JSON.parse(json)
1076       : json;
1077 }
1078
1079
1080 /**
1081  * @returns {string} Returns the string representation of the element.
1082  */
1083 function startingTag(element) {
1084   element = jqLite(element).clone();
1085   try {
1086     // turns out IE does not let you set .html() on elements which
1087     // are not allowed to have children. So we just ignore it.
1088     element.empty();
1089   } catch (e) {}
1090   var elemHtml = jqLite('<div>').append(element).html();
1091   try {
1092     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1093         elemHtml.
1094           match(/^(<[^>]+>)/)[1].
1095           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1096   } catch (e) {
1097     return lowercase(elemHtml);
1098   }
1099
1100 }
1101
1102
1103 /////////////////////////////////////////////////
1104
1105 /**
1106  * Tries to decode the URI component without throwing an exception.
1107  *
1108  * @private
1109  * @param str value potential URI component to check.
1110  * @returns {boolean} True if `value` can be decoded
1111  * with the decodeURIComponent function.
1112  */
1113 function tryDecodeURIComponent(value) {
1114   try {
1115     return decodeURIComponent(value);
1116   } catch (e) {
1117     // Ignore any invalid uri component
1118   }
1119 }
1120
1121
1122 /**
1123  * Parses an escaped url query string into key-value pairs.
1124  * @returns {Object.<string,boolean|Array>}
1125  */
1126 function parseKeyValue(/**string*/keyValue) {
1127   var obj = {}, key_value, key;
1128   forEach((keyValue || "").split('&'), function(keyValue) {
1129     if (keyValue) {
1130       key_value = keyValue.replace(/\+/g,'%20').split('=');
1131       key = tryDecodeURIComponent(key_value[0]);
1132       if (isDefined(key)) {
1133         var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1134         if (!hasOwnProperty.call(obj, key)) {
1135           obj[key] = val;
1136         } else if (isArray(obj[key])) {
1137           obj[key].push(val);
1138         } else {
1139           obj[key] = [obj[key],val];
1140         }
1141       }
1142     }
1143   });
1144   return obj;
1145 }
1146
1147 function toKeyValue(obj) {
1148   var parts = [];
1149   forEach(obj, function(value, key) {
1150     if (isArray(value)) {
1151       forEach(value, function(arrayValue) {
1152         parts.push(encodeUriQuery(key, true) +
1153                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1154       });
1155     } else {
1156     parts.push(encodeUriQuery(key, true) +
1157                (value === true ? '' : '=' + encodeUriQuery(value, true)));
1158     }
1159   });
1160   return parts.length ? parts.join('&') : '';
1161 }
1162
1163
1164 /**
1165  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1166  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1167  * segments:
1168  *    segment       = *pchar
1169  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1170  *    pct-encoded   = "%" HEXDIG HEXDIG
1171  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1172  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1173  *                     / "*" / "+" / "," / ";" / "="
1174  */
1175 function encodeUriSegment(val) {
1176   return encodeUriQuery(val, true).
1177              replace(/%26/gi, '&').
1178              replace(/%3D/gi, '=').
1179              replace(/%2B/gi, '+');
1180 }
1181
1182
1183 /**
1184  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1185  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1186  * encoded per http://tools.ietf.org/html/rfc3986:
1187  *    query       = *( pchar / "/" / "?" )
1188  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1189  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1190  *    pct-encoded   = "%" HEXDIG HEXDIG
1191  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1192  *                     / "*" / "+" / "," / ";" / "="
1193  */
1194 function encodeUriQuery(val, pctEncodeSpaces) {
1195   return encodeURIComponent(val).
1196              replace(/%40/gi, '@').
1197              replace(/%3A/gi, ':').
1198              replace(/%24/g, '$').
1199              replace(/%2C/gi, ',').
1200              replace(/%3B/gi, ';').
1201              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1202 }
1203
1204 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1205
1206 function getNgAttribute(element, ngAttr) {
1207   var attr, i, ii = ngAttrPrefixes.length;
1208   element = jqLite(element);
1209   for (i = 0; i < ii; ++i) {
1210     attr = ngAttrPrefixes[i] + ngAttr;
1211     if (isString(attr = element.attr(attr))) {
1212       return attr;
1213     }
1214   }
1215   return null;
1216 }
1217
1218 /**
1219  * @ngdoc directive
1220  * @name ngApp
1221  * @module ng
1222  *
1223  * @element ANY
1224  * @param {angular.Module} ngApp an optional application
1225  *   {@link angular.module module} name to load.
1226  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1227  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1228  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1229  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1230  *   tracking down the root of these bugs.
1231  *
1232  * @description
1233  *
1234  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1235  * designates the **root element** of the application and is typically placed near the root element
1236  * of the page - e.g. on the `<body>` or `<html>` tags.
1237  *
1238  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1239  * found in the document will be used to define the root element to auto-bootstrap as an
1240  * application. To run multiple applications in an HTML document you must manually bootstrap them using
1241  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1242  *
1243  * You can specify an **AngularJS module** to be used as the root module for the application.  This
1244  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1245  * should contain the application code needed or have dependencies on other modules that will
1246  * contain the code. See {@link angular.module} for more information.
1247  *
1248  * In the example below if the `ngApp` directive were not placed on the `html` element then the
1249  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1250  * would not be resolved to `3`.
1251  *
1252  * `ngApp` is the easiest, and most common way to bootstrap an application.
1253  *
1254  <example module="ngAppDemo">
1255    <file name="index.html">
1256    <div ng-controller="ngAppDemoController">
1257      I can add: {{a}} + {{b}} =  {{ a+b }}
1258    </div>
1259    </file>
1260    <file name="script.js">
1261    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1262      $scope.a = 1;
1263      $scope.b = 2;
1264    });
1265    </file>
1266  </example>
1267  *
1268  * Using `ngStrictDi`, you would see something like this:
1269  *
1270  <example ng-app-included="true">
1271    <file name="index.html">
1272    <div ng-app="ngAppStrictDemo" ng-strict-di>
1273        <div ng-controller="GoodController1">
1274            I can add: {{a}} + {{b}} =  {{ a+b }}
1275
1276            <p>This renders because the controller does not fail to
1277               instantiate, by using explicit annotation style (see
1278               script.js for details)
1279            </p>
1280        </div>
1281
1282        <div ng-controller="GoodController2">
1283            Name: <input ng-model="name"><br />
1284            Hello, {{name}}!
1285
1286            <p>This renders because the controller does not fail to
1287               instantiate, by using explicit annotation style
1288               (see script.js for details)
1289            </p>
1290        </div>
1291
1292        <div ng-controller="BadController">
1293            I can add: {{a}} + {{b}} =  {{ a+b }}
1294
1295            <p>The controller could not be instantiated, due to relying
1296               on automatic function annotations (which are disabled in
1297               strict mode). As such, the content of this section is not
1298               interpolated, and there should be an error in your web console.
1299            </p>
1300        </div>
1301    </div>
1302    </file>
1303    <file name="script.js">
1304    angular.module('ngAppStrictDemo', [])
1305      // BadController will fail to instantiate, due to relying on automatic function annotation,
1306      // rather than an explicit annotation
1307      .controller('BadController', function($scope) {
1308        $scope.a = 1;
1309        $scope.b = 2;
1310      })
1311      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1312      // due to using explicit annotations using the array style and $inject property, respectively.
1313      .controller('GoodController1', ['$scope', function($scope) {
1314        $scope.a = 1;
1315        $scope.b = 2;
1316      }])
1317      .controller('GoodController2', GoodController2);
1318      function GoodController2($scope) {
1319        $scope.name = "World";
1320      }
1321      GoodController2.$inject = ['$scope'];
1322    </file>
1323    <file name="style.css">
1324    div[ng-controller] {
1325        margin-bottom: 1em;
1326        -webkit-border-radius: 4px;
1327        border-radius: 4px;
1328        border: 1px solid;
1329        padding: .5em;
1330    }
1331    div[ng-controller^=Good] {
1332        border-color: #d6e9c6;
1333        background-color: #dff0d8;
1334        color: #3c763d;
1335    }
1336    div[ng-controller^=Bad] {
1337        border-color: #ebccd1;
1338        background-color: #f2dede;
1339        color: #a94442;
1340        margin-bottom: 0;
1341    }
1342    </file>
1343  </example>
1344  */
1345 function angularInit(element, bootstrap) {
1346   var appElement,
1347       module,
1348       config = {};
1349
1350   // The element `element` has priority over any other element
1351   forEach(ngAttrPrefixes, function(prefix) {
1352     var name = prefix + 'app';
1353
1354     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1355       appElement = element;
1356       module = element.getAttribute(name);
1357     }
1358   });
1359   forEach(ngAttrPrefixes, function(prefix) {
1360     var name = prefix + 'app';
1361     var candidate;
1362
1363     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1364       appElement = candidate;
1365       module = candidate.getAttribute(name);
1366     }
1367   });
1368   if (appElement) {
1369     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1370     bootstrap(appElement, module ? [module] : [], config);
1371   }
1372 }
1373
1374 /**
1375  * @ngdoc function
1376  * @name angular.bootstrap
1377  * @module ng
1378  * @description
1379  * Use this function to manually start up angular application.
1380  *
1381  * See: {@link guide/bootstrap Bootstrap}
1382  *
1383  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1384  * They must use {@link ng.directive:ngApp ngApp}.
1385  *
1386  * Angular will detect if it has been loaded into the browser more than once and only allow the
1387  * first loaded script to be bootstrapped and will report a warning to the browser console for
1388  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1389  * multiple instances of Angular try to work on the DOM.
1390  *
1391  * ```html
1392  * <!doctype html>
1393  * <html>
1394  * <body>
1395  * <div ng-controller="WelcomeController">
1396  *   {{greeting}}
1397  * </div>
1398  *
1399  * <script src="angular.js"></script>
1400  * <script>
1401  *   var app = angular.module('demo', [])
1402  *   .controller('WelcomeController', function($scope) {
1403  *       $scope.greeting = 'Welcome!';
1404  *   });
1405  *   angular.bootstrap(document, ['demo']);
1406  * </script>
1407  * </body>
1408  * </html>
1409  * ```
1410  *
1411  * @param {DOMElement} element DOM element which is the root of angular application.
1412  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1413  *     Each item in the array should be the name of a predefined module or a (DI annotated)
1414  *     function that will be invoked by the injector as a `config` block.
1415  *     See: {@link angular.module modules}
1416  * @param {Object=} config an object for defining configuration options for the application. The
1417  *     following keys are supported:
1418  *
1419  * * `strictDi` - disable automatic function annotation for the application. This is meant to
1420  *   assist in finding bugs which break minified code. Defaults to `false`.
1421  *
1422  * @returns {auto.$injector} Returns the newly created injector for this app.
1423  */
1424 function bootstrap(element, modules, config) {
1425   if (!isObject(config)) config = {};
1426   var defaultConfig = {
1427     strictDi: false
1428   };
1429   config = extend(defaultConfig, config);
1430   var doBootstrap = function() {
1431     element = jqLite(element);
1432
1433     if (element.injector()) {
1434       var tag = (element[0] === document) ? 'document' : startingTag(element);
1435       //Encode angle brackets to prevent input from being sanitized to empty string #8683
1436       throw ngMinErr(
1437           'btstrpd',
1438           "App Already Bootstrapped with this Element '{0}'",
1439           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1440     }
1441
1442     modules = modules || [];
1443     modules.unshift(['$provide', function($provide) {
1444       $provide.value('$rootElement', element);
1445     }]);
1446
1447     if (config.debugInfoEnabled) {
1448       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1449       modules.push(['$compileProvider', function($compileProvider) {
1450         $compileProvider.debugInfoEnabled(true);
1451       }]);
1452     }
1453
1454     modules.unshift('ng');
1455     var injector = createInjector(modules, config.strictDi);
1456     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1457        function bootstrapApply(scope, element, compile, injector) {
1458         scope.$apply(function() {
1459           element.data('$injector', injector);
1460           compile(element)(scope);
1461         });
1462       }]
1463     );
1464     return injector;
1465   };
1466
1467   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1468   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1469
1470   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1471     config.debugInfoEnabled = true;
1472     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1473   }
1474
1475   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1476     return doBootstrap();
1477   }
1478
1479   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1480   angular.resumeBootstrap = function(extraModules) {
1481     forEach(extraModules, function(module) {
1482       modules.push(module);
1483     });
1484     return doBootstrap();
1485   };
1486
1487   if (isFunction(angular.resumeDeferredBootstrap)) {
1488     angular.resumeDeferredBootstrap();
1489   }
1490 }
1491
1492 /**
1493  * @ngdoc function
1494  * @name angular.reloadWithDebugInfo
1495  * @module ng
1496  * @description
1497  * Use this function to reload the current application with debug information turned on.
1498  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1499  *
1500  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1501  */
1502 function reloadWithDebugInfo() {
1503   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1504   window.location.reload();
1505 }
1506
1507 /**
1508  * @name angular.getTestability
1509  * @module ng
1510  * @description
1511  * Get the testability service for the instance of Angular on the given
1512  * element.
1513  * @param {DOMElement} element DOM element which is the root of angular application.
1514  */
1515 function getTestability(rootElement) {
1516   var injector = angular.element(rootElement).injector();
1517   if (!injector) {
1518     throw ngMinErr('test',
1519       'no injector found for element argument to getTestability');
1520   }
1521   return injector.get('$$testability');
1522 }
1523
1524 var SNAKE_CASE_REGEXP = /[A-Z]/g;
1525 function snake_case(name, separator) {
1526   separator = separator || '_';
1527   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1528     return (pos ? separator : '') + letter.toLowerCase();
1529   });
1530 }
1531
1532 var bindJQueryFired = false;
1533 var skipDestroyOnNextJQueryCleanData;
1534 function bindJQuery() {
1535   var originalCleanData;
1536
1537   if (bindJQueryFired) {
1538     return;
1539   }
1540
1541   // bind to jQuery if present;
1542   jQuery = window.jQuery;
1543   // Use jQuery if it exists with proper functionality, otherwise default to us.
1544   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1545   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1546   // versions. It will not work for sure with jQuery <1.7, though.
1547   if (jQuery && jQuery.fn.on) {
1548     jqLite = jQuery;
1549     extend(jQuery.fn, {
1550       scope: JQLitePrototype.scope,
1551       isolateScope: JQLitePrototype.isolateScope,
1552       controller: JQLitePrototype.controller,
1553       injector: JQLitePrototype.injector,
1554       inheritedData: JQLitePrototype.inheritedData
1555     });
1556
1557     // All nodes removed from the DOM via various jQuery APIs like .remove()
1558     // are passed through jQuery.cleanData. Monkey-patch this method to fire
1559     // the $destroy event on all removed nodes.
1560     originalCleanData = jQuery.cleanData;
1561     jQuery.cleanData = function(elems) {
1562       var events;
1563       if (!skipDestroyOnNextJQueryCleanData) {
1564         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1565           events = jQuery._data(elem, "events");
1566           if (events && events.$destroy) {
1567             jQuery(elem).triggerHandler('$destroy');
1568           }
1569         }
1570       } else {
1571         skipDestroyOnNextJQueryCleanData = false;
1572       }
1573       originalCleanData(elems);
1574     };
1575   } else {
1576     jqLite = JQLite;
1577   }
1578
1579   angular.element = jqLite;
1580
1581   // Prevent double-proxying.
1582   bindJQueryFired = true;
1583 }
1584
1585 /**
1586  * throw error if the argument is falsy.
1587  */
1588 function assertArg(arg, name, reason) {
1589   if (!arg) {
1590     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1591   }
1592   return arg;
1593 }
1594
1595 function assertArgFn(arg, name, acceptArrayAnnotation) {
1596   if (acceptArrayAnnotation && isArray(arg)) {
1597       arg = arg[arg.length - 1];
1598   }
1599
1600   assertArg(isFunction(arg), name, 'not a function, got ' +
1601       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1602   return arg;
1603 }
1604
1605 /**
1606  * throw error if the name given is hasOwnProperty
1607  * @param  {String} name    the name to test
1608  * @param  {String} context the context in which the name is used, such as module or directive
1609  */
1610 function assertNotHasOwnProperty(name, context) {
1611   if (name === 'hasOwnProperty') {
1612     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1613   }
1614 }
1615
1616 /**
1617  * Return the value accessible from the object by path. Any undefined traversals are ignored
1618  * @param {Object} obj starting object
1619  * @param {String} path path to traverse
1620  * @param {boolean} [bindFnToScope=true]
1621  * @returns {Object} value as accessible by path
1622  */
1623 //TODO(misko): this function needs to be removed
1624 function getter(obj, path, bindFnToScope) {
1625   if (!path) return obj;
1626   var keys = path.split('.');
1627   var key;
1628   var lastInstance = obj;
1629   var len = keys.length;
1630
1631   for (var i = 0; i < len; i++) {
1632     key = keys[i];
1633     if (obj) {
1634       obj = (lastInstance = obj)[key];
1635     }
1636   }
1637   if (!bindFnToScope && isFunction(obj)) {
1638     return bind(lastInstance, obj);
1639   }
1640   return obj;
1641 }
1642
1643 /**
1644  * Return the DOM siblings between the first and last node in the given array.
1645  * @param {Array} array like object
1646  * @returns {jqLite} jqLite collection containing the nodes
1647  */
1648 function getBlockNodes(nodes) {
1649   // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
1650   //             collection, otherwise update the original collection.
1651   var node = nodes[0];
1652   var endNode = nodes[nodes.length - 1];
1653   var blockNodes = [node];
1654
1655   do {
1656     node = node.nextSibling;
1657     if (!node) break;
1658     blockNodes.push(node);
1659   } while (node !== endNode);
1660
1661   return jqLite(blockNodes);
1662 }
1663
1664
1665 /**
1666  * Creates a new object without a prototype. This object is useful for lookup without having to
1667  * guard against prototypically inherited properties via hasOwnProperty.
1668  *
1669  * Related micro-benchmarks:
1670  * - http://jsperf.com/object-create2
1671  * - http://jsperf.com/proto-map-lookup/2
1672  * - http://jsperf.com/for-in-vs-object-keys2
1673  *
1674  * @returns {Object}
1675  */
1676 function createMap() {
1677   return Object.create(null);
1678 }
1679
1680 var NODE_TYPE_ELEMENT = 1;
1681 var NODE_TYPE_ATTRIBUTE = 2;
1682 var NODE_TYPE_TEXT = 3;
1683 var NODE_TYPE_COMMENT = 8;
1684 var NODE_TYPE_DOCUMENT = 9;
1685 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1686
1687 /**
1688  * @ngdoc type
1689  * @name angular.Module
1690  * @module ng
1691  * @description
1692  *
1693  * Interface for configuring angular {@link angular.module modules}.
1694  */
1695
1696 function setupModuleLoader(window) {
1697
1698   var $injectorMinErr = minErr('$injector');
1699   var ngMinErr = minErr('ng');
1700
1701   function ensure(obj, name, factory) {
1702     return obj[name] || (obj[name] = factory());
1703   }
1704
1705   var angular = ensure(window, 'angular', Object);
1706
1707   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1708   angular.$$minErr = angular.$$minErr || minErr;
1709
1710   return ensure(angular, 'module', function() {
1711     /** @type {Object.<string, angular.Module>} */
1712     var modules = {};
1713
1714     /**
1715      * @ngdoc function
1716      * @name angular.module
1717      * @module ng
1718      * @description
1719      *
1720      * The `angular.module` is a global place for creating, registering and retrieving Angular
1721      * modules.
1722      * All modules (angular core or 3rd party) that should be available to an application must be
1723      * registered using this mechanism.
1724      *
1725      * When passed two or more arguments, a new module is created.  If passed only one argument, an
1726      * existing module (the name passed as the first argument to `module`) is retrieved.
1727      *
1728      *
1729      * # Module
1730      *
1731      * A module is a collection of services, directives, controllers, filters, and configuration information.
1732      * `angular.module` is used to configure the {@link auto.$injector $injector}.
1733      *
1734      * ```js
1735      * // Create a new module
1736      * var myModule = angular.module('myModule', []);
1737      *
1738      * // register a new service
1739      * myModule.value('appName', 'MyCoolApp');
1740      *
1741      * // configure existing services inside initialization blocks.
1742      * myModule.config(['$locationProvider', function($locationProvider) {
1743      *   // Configure existing providers
1744      *   $locationProvider.hashPrefix('!');
1745      * }]);
1746      * ```
1747      *
1748      * Then you can create an injector and load your modules like this:
1749      *
1750      * ```js
1751      * var injector = angular.injector(['ng', 'myModule'])
1752      * ```
1753      *
1754      * However it's more likely that you'll just use
1755      * {@link ng.directive:ngApp ngApp} or
1756      * {@link angular.bootstrap} to simplify this process for you.
1757      *
1758      * @param {!string} name The name of the module to create or retrieve.
1759      * @param {!Array.<string>=} requires If specified then new module is being created. If
1760      *        unspecified then the module is being retrieved for further configuration.
1761      * @param {Function=} configFn Optional configuration function for the module. Same as
1762      *        {@link angular.Module#config Module#config()}.
1763      * @returns {module} new module with the {@link angular.Module} api.
1764      */
1765     return function module(name, requires, configFn) {
1766       var assertNotHasOwnProperty = function(name, context) {
1767         if (name === 'hasOwnProperty') {
1768           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1769         }
1770       };
1771
1772       assertNotHasOwnProperty(name, 'module');
1773       if (requires && modules.hasOwnProperty(name)) {
1774         modules[name] = null;
1775       }
1776       return ensure(modules, name, function() {
1777         if (!requires) {
1778           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1779              "the module name or forgot to load it. If registering a module ensure that you " +
1780              "specify the dependencies as the second argument.", name);
1781         }
1782
1783         /** @type {!Array.<Array.<*>>} */
1784         var invokeQueue = [];
1785
1786         /** @type {!Array.<Function>} */
1787         var configBlocks = [];
1788
1789         /** @type {!Array.<Function>} */
1790         var runBlocks = [];
1791
1792         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
1793
1794         /** @type {angular.Module} */
1795         var moduleInstance = {
1796           // Private state
1797           _invokeQueue: invokeQueue,
1798           _configBlocks: configBlocks,
1799           _runBlocks: runBlocks,
1800
1801           /**
1802            * @ngdoc property
1803            * @name angular.Module#requires
1804            * @module ng
1805            *
1806            * @description
1807            * Holds the list of modules which the injector will load before the current module is
1808            * loaded.
1809            */
1810           requires: requires,
1811
1812           /**
1813            * @ngdoc property
1814            * @name angular.Module#name
1815            * @module ng
1816            *
1817            * @description
1818            * Name of the module.
1819            */
1820           name: name,
1821
1822
1823           /**
1824            * @ngdoc method
1825            * @name angular.Module#provider
1826            * @module ng
1827            * @param {string} name service name
1828            * @param {Function} providerType Construction function for creating new instance of the
1829            *                                service.
1830            * @description
1831            * See {@link auto.$provide#provider $provide.provider()}.
1832            */
1833           provider: invokeLater('$provide', 'provider'),
1834
1835           /**
1836            * @ngdoc method
1837            * @name angular.Module#factory
1838            * @module ng
1839            * @param {string} name service name
1840            * @param {Function} providerFunction Function for creating new instance of the service.
1841            * @description
1842            * See {@link auto.$provide#factory $provide.factory()}.
1843            */
1844           factory: invokeLater('$provide', 'factory'),
1845
1846           /**
1847            * @ngdoc method
1848            * @name angular.Module#service
1849            * @module ng
1850            * @param {string} name service name
1851            * @param {Function} constructor A constructor function that will be instantiated.
1852            * @description
1853            * See {@link auto.$provide#service $provide.service()}.
1854            */
1855           service: invokeLater('$provide', 'service'),
1856
1857           /**
1858            * @ngdoc method
1859            * @name angular.Module#value
1860            * @module ng
1861            * @param {string} name service name
1862            * @param {*} object Service instance object.
1863            * @description
1864            * See {@link auto.$provide#value $provide.value()}.
1865            */
1866           value: invokeLater('$provide', 'value'),
1867
1868           /**
1869            * @ngdoc method
1870            * @name angular.Module#constant
1871            * @module ng
1872            * @param {string} name constant name
1873            * @param {*} object Constant value.
1874            * @description
1875            * Because the constant are fixed, they get applied before other provide methods.
1876            * See {@link auto.$provide#constant $provide.constant()}.
1877            */
1878           constant: invokeLater('$provide', 'constant', 'unshift'),
1879
1880           /**
1881            * @ngdoc method
1882            * @name angular.Module#animation
1883            * @module ng
1884            * @param {string} name animation name
1885            * @param {Function} animationFactory Factory function for creating new instance of an
1886            *                                    animation.
1887            * @description
1888            *
1889            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1890            *
1891            *
1892            * Defines an animation hook that can be later used with
1893            * {@link ngAnimate.$animate $animate} service and directives that use this service.
1894            *
1895            * ```js
1896            * module.animation('.animation-name', function($inject1, $inject2) {
1897            *   return {
1898            *     eventName : function(element, done) {
1899            *       //code to run the animation
1900            *       //once complete, then run done()
1901            *       return function cancellationFunction(element) {
1902            *         //code to cancel the animation
1903            *       }
1904            *     }
1905            *   }
1906            * })
1907            * ```
1908            *
1909            * See {@link ng.$animateProvider#register $animateProvider.register()} and
1910            * {@link ngAnimate ngAnimate module} for more information.
1911            */
1912           animation: invokeLater('$animateProvider', 'register'),
1913
1914           /**
1915            * @ngdoc method
1916            * @name angular.Module#filter
1917            * @module ng
1918            * @param {string} name Filter name - this must be a valid angular expression identifier
1919            * @param {Function} filterFactory Factory function for creating new instance of filter.
1920            * @description
1921            * See {@link ng.$filterProvider#register $filterProvider.register()}.
1922            *
1923            * <div class="alert alert-warning">
1924            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
1925            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
1926            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
1927            * (`myapp_subsection_filterx`).
1928            * </div>
1929            */
1930           filter: invokeLater('$filterProvider', 'register'),
1931
1932           /**
1933            * @ngdoc method
1934            * @name angular.Module#controller
1935            * @module ng
1936            * @param {string|Object} name Controller name, or an object map of controllers where the
1937            *    keys are the names and the values are the constructors.
1938            * @param {Function} constructor Controller constructor function.
1939            * @description
1940            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1941            */
1942           controller: invokeLater('$controllerProvider', 'register'),
1943
1944           /**
1945            * @ngdoc method
1946            * @name angular.Module#directive
1947            * @module ng
1948            * @param {string|Object} name Directive name, or an object map of directives where the
1949            *    keys are the names and the values are the factories.
1950            * @param {Function} directiveFactory Factory function for creating new instance of
1951            * directives.
1952            * @description
1953            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1954            */
1955           directive: invokeLater('$compileProvider', 'directive'),
1956
1957           /**
1958            * @ngdoc method
1959            * @name angular.Module#config
1960            * @module ng
1961            * @param {Function} configFn Execute this function on module load. Useful for service
1962            *    configuration.
1963            * @description
1964            * Use this method to register work which needs to be performed on module loading.
1965            * For more about how to configure services, see
1966            * {@link providers#provider-recipe Provider Recipe}.
1967            */
1968           config: config,
1969
1970           /**
1971            * @ngdoc method
1972            * @name angular.Module#run
1973            * @module ng
1974            * @param {Function} initializationFn Execute this function after injector creation.
1975            *    Useful for application initialization.
1976            * @description
1977            * Use this method to register work which should be performed when the injector is done
1978            * loading all modules.
1979            */
1980           run: function(block) {
1981             runBlocks.push(block);
1982             return this;
1983           }
1984         };
1985
1986         if (configFn) {
1987           config(configFn);
1988         }
1989
1990         return moduleInstance;
1991
1992         /**
1993          * @param {string} provider
1994          * @param {string} method
1995          * @param {String=} insertMethod
1996          * @returns {angular.Module}
1997          */
1998         function invokeLater(provider, method, insertMethod, queue) {
1999           if (!queue) queue = invokeQueue;
2000           return function() {
2001             queue[insertMethod || 'push']([provider, method, arguments]);
2002             return moduleInstance;
2003           };
2004         }
2005       });
2006     };
2007   });
2008
2009 }
2010
2011 /* global: toDebugString: true */
2012
2013 function serializeObject(obj) {
2014   var seen = [];
2015
2016   return JSON.stringify(obj, function(key, val) {
2017     val = toJsonReplacer(key, val);
2018     if (isObject(val)) {
2019
2020       if (seen.indexOf(val) >= 0) return '<<already seen>>';
2021
2022       seen.push(val);
2023     }
2024     return val;
2025   });
2026 }
2027
2028 function toDebugString(obj) {
2029   if (typeof obj === 'function') {
2030     return obj.toString().replace(/ \{[\s\S]*$/, '');
2031   } else if (typeof obj === 'undefined') {
2032     return 'undefined';
2033   } else if (typeof obj !== 'string') {
2034     return serializeObject(obj);
2035   }
2036   return obj;
2037 }
2038
2039 /* global angularModule: true,
2040   version: true,
2041
2042   $LocaleProvider,
2043   $CompileProvider,
2044
2045   htmlAnchorDirective,
2046   inputDirective,
2047   inputDirective,
2048   formDirective,
2049   scriptDirective,
2050   selectDirective,
2051   styleDirective,
2052   optionDirective,
2053   ngBindDirective,
2054   ngBindHtmlDirective,
2055   ngBindTemplateDirective,
2056   ngClassDirective,
2057   ngClassEvenDirective,
2058   ngClassOddDirective,
2059   ngCspDirective,
2060   ngCloakDirective,
2061   ngControllerDirective,
2062   ngFormDirective,
2063   ngHideDirective,
2064   ngIfDirective,
2065   ngIncludeDirective,
2066   ngIncludeFillContentDirective,
2067   ngInitDirective,
2068   ngNonBindableDirective,
2069   ngPluralizeDirective,
2070   ngRepeatDirective,
2071   ngShowDirective,
2072   ngStyleDirective,
2073   ngSwitchDirective,
2074   ngSwitchWhenDirective,
2075   ngSwitchDefaultDirective,
2076   ngOptionsDirective,
2077   ngTranscludeDirective,
2078   ngModelDirective,
2079   ngListDirective,
2080   ngChangeDirective,
2081   patternDirective,
2082   patternDirective,
2083   requiredDirective,
2084   requiredDirective,
2085   minlengthDirective,
2086   minlengthDirective,
2087   maxlengthDirective,
2088   maxlengthDirective,
2089   ngValueDirective,
2090   ngModelOptionsDirective,
2091   ngAttributeAliasDirectives,
2092   ngEventDirectives,
2093
2094   $AnchorScrollProvider,
2095   $AnimateProvider,
2096   $BrowserProvider,
2097   $CacheFactoryProvider,
2098   $ControllerProvider,
2099   $DocumentProvider,
2100   $ExceptionHandlerProvider,
2101   $FilterProvider,
2102   $InterpolateProvider,
2103   $IntervalProvider,
2104   $HttpProvider,
2105   $HttpBackendProvider,
2106   $LocationProvider,
2107   $LogProvider,
2108   $ParseProvider,
2109   $RootScopeProvider,
2110   $QProvider,
2111   $$QProvider,
2112   $$SanitizeUriProvider,
2113   $SceProvider,
2114   $SceDelegateProvider,
2115   $SnifferProvider,
2116   $TemplateCacheProvider,
2117   $TemplateRequestProvider,
2118   $$TestabilityProvider,
2119   $TimeoutProvider,
2120   $$RAFProvider,
2121   $$AsyncCallbackProvider,
2122   $WindowProvider,
2123   $$jqLiteProvider
2124 */
2125
2126
2127 /**
2128  * @ngdoc object
2129  * @name angular.version
2130  * @module ng
2131  * @description
2132  * An object that contains information about the current AngularJS version. This object has the
2133  * following properties:
2134  *
2135  * - `full` – `{string}` – Full version string, such as "0.9.18".
2136  * - `major` – `{number}` – Major version number, such as "0".
2137  * - `minor` – `{number}` – Minor version number, such as "9".
2138  * - `dot` – `{number}` – Dot version number, such as "18".
2139  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2140  */
2141 var version = {
2142   full: '1.3.20',    // all of these placeholder strings will be replaced by grunt's
2143   major: 1,    // package task
2144   minor: 3,
2145   dot: 20,
2146   codeName: 'shallow-translucence'
2147 };
2148
2149
2150 function publishExternalAPI(angular) {
2151   extend(angular, {
2152     'bootstrap': bootstrap,
2153     'copy': copy,
2154     'extend': extend,
2155     'equals': equals,
2156     'element': jqLite,
2157     'forEach': forEach,
2158     'injector': createInjector,
2159     'noop': noop,
2160     'bind': bind,
2161     'toJson': toJson,
2162     'fromJson': fromJson,
2163     'identity': identity,
2164     'isUndefined': isUndefined,
2165     'isDefined': isDefined,
2166     'isString': isString,
2167     'isFunction': isFunction,
2168     'isObject': isObject,
2169     'isNumber': isNumber,
2170     'isElement': isElement,
2171     'isArray': isArray,
2172     'version': version,
2173     'isDate': isDate,
2174     'lowercase': lowercase,
2175     'uppercase': uppercase,
2176     'callbacks': {counter: 0},
2177     'getTestability': getTestability,
2178     '$$minErr': minErr,
2179     '$$csp': csp,
2180     'reloadWithDebugInfo': reloadWithDebugInfo
2181   });
2182
2183   angularModule = setupModuleLoader(window);
2184   try {
2185     angularModule('ngLocale');
2186   } catch (e) {
2187     angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2188   }
2189
2190   angularModule('ng', ['ngLocale'], ['$provide',
2191     function ngModule($provide) {
2192       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2193       $provide.provider({
2194         $$sanitizeUri: $$SanitizeUriProvider
2195       });
2196       $provide.provider('$compile', $CompileProvider).
2197         directive({
2198             a: htmlAnchorDirective,
2199             input: inputDirective,
2200             textarea: inputDirective,
2201             form: formDirective,
2202             script: scriptDirective,
2203             select: selectDirective,
2204             style: styleDirective,
2205             option: optionDirective,
2206             ngBind: ngBindDirective,
2207             ngBindHtml: ngBindHtmlDirective,
2208             ngBindTemplate: ngBindTemplateDirective,
2209             ngClass: ngClassDirective,
2210             ngClassEven: ngClassEvenDirective,
2211             ngClassOdd: ngClassOddDirective,
2212             ngCloak: ngCloakDirective,
2213             ngController: ngControllerDirective,
2214             ngForm: ngFormDirective,
2215             ngHide: ngHideDirective,
2216             ngIf: ngIfDirective,
2217             ngInclude: ngIncludeDirective,
2218             ngInit: ngInitDirective,
2219             ngNonBindable: ngNonBindableDirective,
2220             ngPluralize: ngPluralizeDirective,
2221             ngRepeat: ngRepeatDirective,
2222             ngShow: ngShowDirective,
2223             ngStyle: ngStyleDirective,
2224             ngSwitch: ngSwitchDirective,
2225             ngSwitchWhen: ngSwitchWhenDirective,
2226             ngSwitchDefault: ngSwitchDefaultDirective,
2227             ngOptions: ngOptionsDirective,
2228             ngTransclude: ngTranscludeDirective,
2229             ngModel: ngModelDirective,
2230             ngList: ngListDirective,
2231             ngChange: ngChangeDirective,
2232             pattern: patternDirective,
2233             ngPattern: patternDirective,
2234             required: requiredDirective,
2235             ngRequired: requiredDirective,
2236             minlength: minlengthDirective,
2237             ngMinlength: minlengthDirective,
2238             maxlength: maxlengthDirective,
2239             ngMaxlength: maxlengthDirective,
2240             ngValue: ngValueDirective,
2241             ngModelOptions: ngModelOptionsDirective
2242         }).
2243         directive({
2244           ngInclude: ngIncludeFillContentDirective
2245         }).
2246         directive(ngAttributeAliasDirectives).
2247         directive(ngEventDirectives);
2248       $provide.provider({
2249         $anchorScroll: $AnchorScrollProvider,
2250         $animate: $AnimateProvider,
2251         $browser: $BrowserProvider,
2252         $cacheFactory: $CacheFactoryProvider,
2253         $controller: $ControllerProvider,
2254         $document: $DocumentProvider,
2255         $exceptionHandler: $ExceptionHandlerProvider,
2256         $filter: $FilterProvider,
2257         $interpolate: $InterpolateProvider,
2258         $interval: $IntervalProvider,
2259         $http: $HttpProvider,
2260         $httpBackend: $HttpBackendProvider,
2261         $location: $LocationProvider,
2262         $log: $LogProvider,
2263         $parse: $ParseProvider,
2264         $rootScope: $RootScopeProvider,
2265         $q: $QProvider,
2266         $$q: $$QProvider,
2267         $sce: $SceProvider,
2268         $sceDelegate: $SceDelegateProvider,
2269         $sniffer: $SnifferProvider,
2270         $templateCache: $TemplateCacheProvider,
2271         $templateRequest: $TemplateRequestProvider,
2272         $$testability: $$TestabilityProvider,
2273         $timeout: $TimeoutProvider,
2274         $window: $WindowProvider,
2275         $$rAF: $$RAFProvider,
2276         $$asyncCallback: $$AsyncCallbackProvider,
2277         $$jqLite: $$jqLiteProvider
2278       });
2279     }
2280   ]);
2281 }
2282
2283 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2284  *     Any commits to this file should be reviewed with security in mind.  *
2285  *   Changes to this file can potentially create security vulnerabilities. *
2286  *          An approval from 2 Core members with history of modifying      *
2287  *                         this file is required.                          *
2288  *                                                                         *
2289  *  Does the change somehow allow for arbitrary javascript to be executed? *
2290  *    Or allows for someone to change the prototype of built-in objects?   *
2291  *     Or gives undesired access to variables likes document or window?    *
2292  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2293
2294 /* global JQLitePrototype: true,
2295   addEventListenerFn: true,
2296   removeEventListenerFn: true,
2297   BOOLEAN_ATTR: true,
2298   ALIASED_ATTR: true,
2299 */
2300
2301 //////////////////////////////////
2302 //JQLite
2303 //////////////////////////////////
2304
2305 /**
2306  * @ngdoc function
2307  * @name angular.element
2308  * @module ng
2309  * @kind function
2310  *
2311  * @description
2312  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2313  *
2314  * If jQuery is available, `angular.element` is an alias for the
2315  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2316  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2317  *
2318  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2319  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2320  * commonly needed functionality with the goal of having a very small footprint.</div>
2321  *
2322  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2323  *
2324  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2325  * jqLite; they are never raw DOM references.</div>
2326  *
2327  * ## Angular's jqLite
2328  * jqLite provides only the following jQuery methods:
2329  *
2330  * - [`addClass()`](http://api.jquery.com/addClass/)
2331  * - [`after()`](http://api.jquery.com/after/)
2332  * - [`append()`](http://api.jquery.com/append/)
2333  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2334  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2335  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2336  * - [`clone()`](http://api.jquery.com/clone/)
2337  * - [`contents()`](http://api.jquery.com/contents/)
2338  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
2339  * - [`data()`](http://api.jquery.com/data/)
2340  * - [`detach()`](http://api.jquery.com/detach/)
2341  * - [`empty()`](http://api.jquery.com/empty/)
2342  * - [`eq()`](http://api.jquery.com/eq/)
2343  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2344  * - [`hasClass()`](http://api.jquery.com/hasClass/)
2345  * - [`html()`](http://api.jquery.com/html/)
2346  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2347  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2348  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2349  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2350  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2351  * - [`prepend()`](http://api.jquery.com/prepend/)
2352  * - [`prop()`](http://api.jquery.com/prop/)
2353  * - [`ready()`](http://api.jquery.com/ready/)
2354  * - [`remove()`](http://api.jquery.com/remove/)
2355  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2356  * - [`removeClass()`](http://api.jquery.com/removeClass/)
2357  * - [`removeData()`](http://api.jquery.com/removeData/)
2358  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2359  * - [`text()`](http://api.jquery.com/text/)
2360  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2361  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2362  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2363  * - [`val()`](http://api.jquery.com/val/)
2364  * - [`wrap()`](http://api.jquery.com/wrap/)
2365  *
2366  * ## jQuery/jqLite Extras
2367  * Angular also provides the following additional methods and events to both jQuery and jqLite:
2368  *
2369  * ### Events
2370  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2371  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2372  *    element before it is removed.
2373  *
2374  * ### Methods
2375  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2376  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2377  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2378  *   `'ngModel'`).
2379  * - `injector()` - retrieves the injector of the current element or its parent.
2380  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2381  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2382  *   be enabled.
2383  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2384  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2385  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2386  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2387  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2388  *   parent element is reached.
2389  *
2390  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2391  * @returns {Object} jQuery object.
2392  */
2393
2394 JQLite.expando = 'ng339';
2395
2396 var jqCache = JQLite.cache = {},
2397     jqId = 1,
2398     addEventListenerFn = function(element, type, fn) {
2399       element.addEventListener(type, fn, false);
2400     },
2401     removeEventListenerFn = function(element, type, fn) {
2402       element.removeEventListener(type, fn, false);
2403     };
2404
2405 /*
2406  * !!! This is an undocumented "private" function !!!
2407  */
2408 JQLite._data = function(node) {
2409   //jQuery always returns an object on cache miss
2410   return this.cache[node[this.expando]] || {};
2411 };
2412
2413 function jqNextId() { return ++jqId; }
2414
2415
2416 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2417 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2418 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2419 var jqLiteMinErr = minErr('jqLite');
2420
2421 /**
2422  * Converts snake_case to camelCase.
2423  * Also there is special case for Moz prefix starting with upper case letter.
2424  * @param name Name to normalize
2425  */
2426 function camelCase(name) {
2427   return name.
2428     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2429       return offset ? letter.toUpperCase() : letter;
2430     }).
2431     replace(MOZ_HACK_REGEXP, 'Moz$1');
2432 }
2433
2434 var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2435 var HTML_REGEXP = /<|&#?\w+;/;
2436 var TAG_NAME_REGEXP = /<([\w:]+)/;
2437 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2438
2439 var wrapMap = {
2440   'option': [1, '<select multiple="multiple">', '</select>'],
2441
2442   'thead': [1, '<table>', '</table>'],
2443   'col': [2, '<table><colgroup>', '</colgroup></table>'],
2444   'tr': [2, '<table><tbody>', '</tbody></table>'],
2445   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2446   '_default': [0, "", ""]
2447 };
2448
2449 wrapMap.optgroup = wrapMap.option;
2450 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2451 wrapMap.th = wrapMap.td;
2452
2453
2454 function jqLiteIsTextNode(html) {
2455   return !HTML_REGEXP.test(html);
2456 }
2457
2458 function jqLiteAcceptsData(node) {
2459   // The window object can accept data but has no nodeType
2460   // Otherwise we are only interested in elements (1) and documents (9)
2461   var nodeType = node.nodeType;
2462   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2463 }
2464
2465 function jqLiteBuildFragment(html, context) {
2466   var tmp, tag, wrap,
2467       fragment = context.createDocumentFragment(),
2468       nodes = [], i;
2469
2470   if (jqLiteIsTextNode(html)) {
2471     // Convert non-html into a text node
2472     nodes.push(context.createTextNode(html));
2473   } else {
2474     // Convert html into DOM nodes
2475     tmp = tmp || fragment.appendChild(context.createElement("div"));
2476     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2477     wrap = wrapMap[tag] || wrapMap._default;
2478     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2479
2480     // Descend through wrappers to the right content
2481     i = wrap[0];
2482     while (i--) {
2483       tmp = tmp.lastChild;
2484     }
2485
2486     nodes = concat(nodes, tmp.childNodes);
2487
2488     tmp = fragment.firstChild;
2489     tmp.textContent = "";
2490   }
2491
2492   // Remove wrapper from fragment
2493   fragment.textContent = "";
2494   fragment.innerHTML = ""; // Clear inner HTML
2495   forEach(nodes, function(node) {
2496     fragment.appendChild(node);
2497   });
2498
2499   return fragment;
2500 }
2501
2502 function jqLiteParseHTML(html, context) {
2503   context = context || document;
2504   var parsed;
2505
2506   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2507     return [context.createElement(parsed[1])];
2508   }
2509
2510   if ((parsed = jqLiteBuildFragment(html, context))) {
2511     return parsed.childNodes;
2512   }
2513
2514   return [];
2515 }
2516
2517 /////////////////////////////////////////////
2518 function JQLite(element) {
2519   if (element instanceof JQLite) {
2520     return element;
2521   }
2522
2523   var argIsString;
2524
2525   if (isString(element)) {
2526     element = trim(element);
2527     argIsString = true;
2528   }
2529   if (!(this instanceof JQLite)) {
2530     if (argIsString && element.charAt(0) != '<') {
2531       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2532     }
2533     return new JQLite(element);
2534   }
2535
2536   if (argIsString) {
2537     jqLiteAddNodes(this, jqLiteParseHTML(element));
2538   } else {
2539     jqLiteAddNodes(this, element);
2540   }
2541 }
2542
2543 function jqLiteClone(element) {
2544   return element.cloneNode(true);
2545 }
2546
2547 function jqLiteDealoc(element, onlyDescendants) {
2548   if (!onlyDescendants) jqLiteRemoveData(element);
2549
2550   if (element.querySelectorAll) {
2551     var descendants = element.querySelectorAll('*');
2552     for (var i = 0, l = descendants.length; i < l; i++) {
2553       jqLiteRemoveData(descendants[i]);
2554     }
2555   }
2556 }
2557
2558 function jqLiteOff(element, type, fn, unsupported) {
2559   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2560
2561   var expandoStore = jqLiteExpandoStore(element);
2562   var events = expandoStore && expandoStore.events;
2563   var handle = expandoStore && expandoStore.handle;
2564
2565   if (!handle) return; //no listeners registered
2566
2567   if (!type) {
2568     for (type in events) {
2569       if (type !== '$destroy') {
2570         removeEventListenerFn(element, type, handle);
2571       }
2572       delete events[type];
2573     }
2574   } else {
2575     forEach(type.split(' '), function(type) {
2576       if (isDefined(fn)) {
2577         var listenerFns = events[type];
2578         arrayRemove(listenerFns || [], fn);
2579         if (listenerFns && listenerFns.length > 0) {
2580           return;
2581         }
2582       }
2583
2584       removeEventListenerFn(element, type, handle);
2585       delete events[type];
2586     });
2587   }
2588 }
2589
2590 function jqLiteRemoveData(element, name) {
2591   var expandoId = element.ng339;
2592   var expandoStore = expandoId && jqCache[expandoId];
2593
2594   if (expandoStore) {
2595     if (name) {
2596       delete expandoStore.data[name];
2597       return;
2598     }
2599
2600     if (expandoStore.handle) {
2601       if (expandoStore.events.$destroy) {
2602         expandoStore.handle({}, '$destroy');
2603       }
2604       jqLiteOff(element);
2605     }
2606     delete jqCache[expandoId];
2607     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2608   }
2609 }
2610
2611
2612 function jqLiteExpandoStore(element, createIfNecessary) {
2613   var expandoId = element.ng339,
2614       expandoStore = expandoId && jqCache[expandoId];
2615
2616   if (createIfNecessary && !expandoStore) {
2617     element.ng339 = expandoId = jqNextId();
2618     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2619   }
2620
2621   return expandoStore;
2622 }
2623
2624
2625 function jqLiteData(element, key, value) {
2626   if (jqLiteAcceptsData(element)) {
2627
2628     var isSimpleSetter = isDefined(value);
2629     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2630     var massGetter = !key;
2631     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2632     var data = expandoStore && expandoStore.data;
2633
2634     if (isSimpleSetter) { // data('key', value)
2635       data[key] = value;
2636     } else {
2637       if (massGetter) {  // data()
2638         return data;
2639       } else {
2640         if (isSimpleGetter) { // data('key')
2641           // don't force creation of expandoStore if it doesn't exist yet
2642           return data && data[key];
2643         } else { // mass-setter: data({key1: val1, key2: val2})
2644           extend(data, key);
2645         }
2646       }
2647     }
2648   }
2649 }
2650
2651 function jqLiteHasClass(element, selector) {
2652   if (!element.getAttribute) return false;
2653   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2654       indexOf(" " + selector + " ") > -1);
2655 }
2656
2657 function jqLiteRemoveClass(element, cssClasses) {
2658   if (cssClasses && element.setAttribute) {
2659     forEach(cssClasses.split(' '), function(cssClass) {
2660       element.setAttribute('class', trim(
2661           (" " + (element.getAttribute('class') || '') + " ")
2662           .replace(/[\n\t]/g, " ")
2663           .replace(" " + trim(cssClass) + " ", " "))
2664       );
2665     });
2666   }
2667 }
2668
2669 function jqLiteAddClass(element, cssClasses) {
2670   if (cssClasses && element.setAttribute) {
2671     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2672                             .replace(/[\n\t]/g, " ");
2673
2674     forEach(cssClasses.split(' '), function(cssClass) {
2675       cssClass = trim(cssClass);
2676       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2677         existingClasses += cssClass + ' ';
2678       }
2679     });
2680
2681     element.setAttribute('class', trim(existingClasses));
2682   }
2683 }
2684
2685
2686 function jqLiteAddNodes(root, elements) {
2687   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
2688
2689   if (elements) {
2690
2691     // if a Node (the most common case)
2692     if (elements.nodeType) {
2693       root[root.length++] = elements;
2694     } else {
2695       var length = elements.length;
2696
2697       // if an Array or NodeList and not a Window
2698       if (typeof length === 'number' && elements.window !== elements) {
2699         if (length) {
2700           for (var i = 0; i < length; i++) {
2701             root[root.length++] = elements[i];
2702           }
2703         }
2704       } else {
2705         root[root.length++] = elements;
2706       }
2707     }
2708   }
2709 }
2710
2711
2712 function jqLiteController(element, name) {
2713   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
2714 }
2715
2716 function jqLiteInheritedData(element, name, value) {
2717   // if element is the document object work with the html element instead
2718   // this makes $(document).scope() possible
2719   if (element.nodeType == NODE_TYPE_DOCUMENT) {
2720     element = element.documentElement;
2721   }
2722   var names = isArray(name) ? name : [name];
2723
2724   while (element) {
2725     for (var i = 0, ii = names.length; i < ii; i++) {
2726       if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2727     }
2728
2729     // If dealing with a document fragment node with a host element, and no parent, use the host
2730     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2731     // to lookup parent controllers.
2732     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
2733   }
2734 }
2735
2736 function jqLiteEmpty(element) {
2737   jqLiteDealoc(element, true);
2738   while (element.firstChild) {
2739     element.removeChild(element.firstChild);
2740   }
2741 }
2742
2743 function jqLiteRemove(element, keepData) {
2744   if (!keepData) jqLiteDealoc(element);
2745   var parent = element.parentNode;
2746   if (parent) parent.removeChild(element);
2747 }
2748
2749
2750 function jqLiteDocumentLoaded(action, win) {
2751   win = win || window;
2752   if (win.document.readyState === 'complete') {
2753     // Force the action to be run async for consistent behaviour
2754     // from the action's point of view
2755     // i.e. it will definitely not be in a $apply
2756     win.setTimeout(action);
2757   } else {
2758     // No need to unbind this handler as load is only ever called once
2759     jqLite(win).on('load', action);
2760   }
2761 }
2762
2763 //////////////////////////////////////////
2764 // Functions which are declared directly.
2765 //////////////////////////////////////////
2766 var JQLitePrototype = JQLite.prototype = {
2767   ready: function(fn) {
2768     var fired = false;
2769
2770     function trigger() {
2771       if (fired) return;
2772       fired = true;
2773       fn();
2774     }
2775
2776     // check if document is already loaded
2777     if (document.readyState === 'complete') {
2778       setTimeout(trigger);
2779     } else {
2780       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2781       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2782       // jshint -W064
2783       JQLite(window).on('load', trigger); // fallback to window.onload for others
2784       // jshint +W064
2785     }
2786   },
2787   toString: function() {
2788     var value = [];
2789     forEach(this, function(e) { value.push('' + e);});
2790     return '[' + value.join(', ') + ']';
2791   },
2792
2793   eq: function(index) {
2794       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2795   },
2796
2797   length: 0,
2798   push: push,
2799   sort: [].sort,
2800   splice: [].splice
2801 };
2802
2803 //////////////////////////////////////////
2804 // Functions iterating getter/setters.
2805 // these functions return self on setter and
2806 // value on get.
2807 //////////////////////////////////////////
2808 var BOOLEAN_ATTR = {};
2809 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2810   BOOLEAN_ATTR[lowercase(value)] = value;
2811 });
2812 var BOOLEAN_ELEMENTS = {};
2813 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2814   BOOLEAN_ELEMENTS[value] = true;
2815 });
2816 var ALIASED_ATTR = {
2817   'ngMinlength': 'minlength',
2818   'ngMaxlength': 'maxlength',
2819   'ngMin': 'min',
2820   'ngMax': 'max',
2821   'ngPattern': 'pattern'
2822 };
2823
2824 function getBooleanAttrName(element, name) {
2825   // check dom last since we will most likely fail on name
2826   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2827
2828   // booleanAttr is here twice to minimize DOM access
2829   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
2830 }
2831
2832 function getAliasedAttrName(element, name) {
2833   var nodeName = element.nodeName;
2834   return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
2835 }
2836
2837 forEach({
2838   data: jqLiteData,
2839   removeData: jqLiteRemoveData
2840 }, function(fn, name) {
2841   JQLite[name] = fn;
2842 });
2843
2844 forEach({
2845   data: jqLiteData,
2846   inheritedData: jqLiteInheritedData,
2847
2848   scope: function(element) {
2849     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2850     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2851   },
2852
2853   isolateScope: function(element) {
2854     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2855     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2856   },
2857
2858   controller: jqLiteController,
2859
2860   injector: function(element) {
2861     return jqLiteInheritedData(element, '$injector');
2862   },
2863
2864   removeAttr: function(element, name) {
2865     element.removeAttribute(name);
2866   },
2867
2868   hasClass: jqLiteHasClass,
2869
2870   css: function(element, name, value) {
2871     name = camelCase(name);
2872
2873     if (isDefined(value)) {
2874       element.style[name] = value;
2875     } else {
2876       return element.style[name];
2877     }
2878   },
2879
2880   attr: function(element, name, value) {
2881     var nodeType = element.nodeType;
2882     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
2883       return;
2884     }
2885     var lowercasedName = lowercase(name);
2886     if (BOOLEAN_ATTR[lowercasedName]) {
2887       if (isDefined(value)) {
2888         if (!!value) {
2889           element[name] = true;
2890           element.setAttribute(name, lowercasedName);
2891         } else {
2892           element[name] = false;
2893           element.removeAttribute(lowercasedName);
2894         }
2895       } else {
2896         return (element[name] ||
2897                  (element.attributes.getNamedItem(name) || noop).specified)
2898                ? lowercasedName
2899                : undefined;
2900       }
2901     } else if (isDefined(value)) {
2902       element.setAttribute(name, value);
2903     } else if (element.getAttribute) {
2904       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2905       // some elements (e.g. Document) don't have get attribute, so return undefined
2906       var ret = element.getAttribute(name, 2);
2907       // normalize non-existing attributes to undefined (as jQuery)
2908       return ret === null ? undefined : ret;
2909     }
2910   },
2911
2912   prop: function(element, name, value) {
2913     if (isDefined(value)) {
2914       element[name] = value;
2915     } else {
2916       return element[name];
2917     }
2918   },
2919
2920   text: (function() {
2921     getText.$dv = '';
2922     return getText;
2923
2924     function getText(element, value) {
2925       if (isUndefined(value)) {
2926         var nodeType = element.nodeType;
2927         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
2928       }
2929       element.textContent = value;
2930     }
2931   })(),
2932
2933   val: function(element, value) {
2934     if (isUndefined(value)) {
2935       if (element.multiple && nodeName_(element) === 'select') {
2936         var result = [];
2937         forEach(element.options, function(option) {
2938           if (option.selected) {
2939             result.push(option.value || option.text);
2940           }
2941         });
2942         return result.length === 0 ? null : result;
2943       }
2944       return element.value;
2945     }
2946     element.value = value;
2947   },
2948
2949   html: function(element, value) {
2950     if (isUndefined(value)) {
2951       return element.innerHTML;
2952     }
2953     jqLiteDealoc(element, true);
2954     element.innerHTML = value;
2955   },
2956
2957   empty: jqLiteEmpty
2958 }, function(fn, name) {
2959   /**
2960    * Properties: writes return selection, reads return first value
2961    */
2962   JQLite.prototype[name] = function(arg1, arg2) {
2963     var i, key;
2964     var nodeCount = this.length;
2965
2966     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2967     // in a way that survives minification.
2968     // jqLiteEmpty takes no arguments but is a setter.
2969     if (fn !== jqLiteEmpty &&
2970         (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2971       if (isObject(arg1)) {
2972
2973         // we are a write, but the object properties are the key/values
2974         for (i = 0; i < nodeCount; i++) {
2975           if (fn === jqLiteData) {
2976             // data() takes the whole object in jQuery
2977             fn(this[i], arg1);
2978           } else {
2979             for (key in arg1) {
2980               fn(this[i], key, arg1[key]);
2981             }
2982           }
2983         }
2984         // return self for chaining
2985         return this;
2986       } else {
2987         // we are a read, so read the first child.
2988         // TODO: do we still need this?
2989         var value = fn.$dv;
2990         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2991         var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2992         for (var j = 0; j < jj; j++) {
2993           var nodeValue = fn(this[j], arg1, arg2);
2994           value = value ? value + nodeValue : nodeValue;
2995         }
2996         return value;
2997       }
2998     } else {
2999       // we are a write, so apply to all children
3000       for (i = 0; i < nodeCount; i++) {
3001         fn(this[i], arg1, arg2);
3002       }
3003       // return self for chaining
3004       return this;
3005     }
3006   };
3007 });
3008
3009 function createEventHandler(element, events) {
3010   var eventHandler = function(event, type) {
3011     // jQuery specific api
3012     event.isDefaultPrevented = function() {
3013       return event.defaultPrevented;
3014     };
3015
3016     var eventFns = events[type || event.type];
3017     var eventFnsLength = eventFns ? eventFns.length : 0;
3018
3019     if (!eventFnsLength) return;
3020
3021     if (isUndefined(event.immediatePropagationStopped)) {
3022       var originalStopImmediatePropagation = event.stopImmediatePropagation;
3023       event.stopImmediatePropagation = function() {
3024         event.immediatePropagationStopped = true;
3025
3026         if (event.stopPropagation) {
3027           event.stopPropagation();
3028         }
3029
3030         if (originalStopImmediatePropagation) {
3031           originalStopImmediatePropagation.call(event);
3032         }
3033       };
3034     }
3035
3036     event.isImmediatePropagationStopped = function() {
3037       return event.immediatePropagationStopped === true;
3038     };
3039
3040     // Copy event handlers in case event handlers array is modified during execution.
3041     if ((eventFnsLength > 1)) {
3042       eventFns = shallowCopy(eventFns);
3043     }
3044
3045     for (var i = 0; i < eventFnsLength; i++) {
3046       if (!event.isImmediatePropagationStopped()) {
3047         eventFns[i].call(element, event);
3048       }
3049     }
3050   };
3051
3052   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3053   //       events on `element`
3054   eventHandler.elem = element;
3055   return eventHandler;
3056 }
3057
3058 //////////////////////////////////////////
3059 // Functions iterating traversal.
3060 // These functions chain results into a single
3061 // selector.
3062 //////////////////////////////////////////
3063 forEach({
3064   removeData: jqLiteRemoveData,
3065
3066   on: function jqLiteOn(element, type, fn, unsupported) {
3067     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3068
3069     // Do not add event handlers to non-elements because they will not be cleaned up.
3070     if (!jqLiteAcceptsData(element)) {
3071       return;
3072     }
3073
3074     var expandoStore = jqLiteExpandoStore(element, true);
3075     var events = expandoStore.events;
3076     var handle = expandoStore.handle;
3077
3078     if (!handle) {
3079       handle = expandoStore.handle = createEventHandler(element, events);
3080     }
3081
3082     // http://jsperf.com/string-indexof-vs-split
3083     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3084     var i = types.length;
3085
3086     while (i--) {
3087       type = types[i];
3088       var eventFns = events[type];
3089
3090       if (!eventFns) {
3091         events[type] = [];
3092
3093         if (type === 'mouseenter' || type === 'mouseleave') {
3094           // Refer to jQuery's implementation of mouseenter & mouseleave
3095           // Read about mouseenter and mouseleave:
3096           // http://www.quirksmode.org/js/events_mouse.html#link8
3097
3098           jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
3099             var target = this, related = event.relatedTarget;
3100             // For mousenter/leave call the handler if related is outside the target.
3101             // NB: No relatedTarget if the mouse left/entered the browser window
3102             if (!related || (related !== target && !target.contains(related))) {
3103               handle(event, type);
3104             }
3105           });
3106
3107         } else {
3108           if (type !== '$destroy') {
3109             addEventListenerFn(element, type, handle);
3110           }
3111         }
3112         eventFns = events[type];
3113       }
3114       eventFns.push(fn);
3115     }
3116   },
3117
3118   off: jqLiteOff,
3119
3120   one: function(element, type, fn) {
3121     element = jqLite(element);
3122
3123     //add the listener twice so that when it is called
3124     //you can remove the original function and still be
3125     //able to call element.off(ev, fn) normally
3126     element.on(type, function onFn() {
3127       element.off(type, fn);
3128       element.off(type, onFn);
3129     });
3130     element.on(type, fn);
3131   },
3132
3133   replaceWith: function(element, replaceNode) {
3134     var index, parent = element.parentNode;
3135     jqLiteDealoc(element);
3136     forEach(new JQLite(replaceNode), function(node) {
3137       if (index) {
3138         parent.insertBefore(node, index.nextSibling);
3139       } else {
3140         parent.replaceChild(node, element);
3141       }
3142       index = node;
3143     });
3144   },
3145
3146   children: function(element) {
3147     var children = [];
3148     forEach(element.childNodes, function(element) {
3149       if (element.nodeType === NODE_TYPE_ELEMENT)
3150         children.push(element);
3151     });
3152     return children;
3153   },
3154
3155   contents: function(element) {
3156     return element.contentDocument || element.childNodes || [];
3157   },
3158
3159   append: function(element, node) {
3160     var nodeType = element.nodeType;
3161     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3162
3163     node = new JQLite(node);
3164
3165     for (var i = 0, ii = node.length; i < ii; i++) {
3166       var child = node[i];
3167       element.appendChild(child);
3168     }
3169   },
3170
3171   prepend: function(element, node) {
3172     if (element.nodeType === NODE_TYPE_ELEMENT) {
3173       var index = element.firstChild;
3174       forEach(new JQLite(node), function(child) {
3175         element.insertBefore(child, index);
3176       });
3177     }
3178   },
3179
3180   wrap: function(element, wrapNode) {
3181     wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3182     var parent = element.parentNode;
3183     if (parent) {
3184       parent.replaceChild(wrapNode, element);
3185     }
3186     wrapNode.appendChild(element);
3187   },
3188
3189   remove: jqLiteRemove,
3190
3191   detach: function(element) {
3192     jqLiteRemove(element, true);
3193   },
3194
3195   after: function(element, newElement) {
3196     var index = element, parent = element.parentNode;
3197     newElement = new JQLite(newElement);
3198
3199     for (var i = 0, ii = newElement.length; i < ii; i++) {
3200       var node = newElement[i];
3201       parent.insertBefore(node, index.nextSibling);
3202       index = node;
3203     }
3204   },
3205
3206   addClass: jqLiteAddClass,
3207   removeClass: jqLiteRemoveClass,
3208
3209   toggleClass: function(element, selector, condition) {
3210     if (selector) {
3211       forEach(selector.split(' '), function(className) {
3212         var classCondition = condition;
3213         if (isUndefined(classCondition)) {
3214           classCondition = !jqLiteHasClass(element, className);
3215         }
3216         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3217       });
3218     }
3219   },
3220
3221   parent: function(element) {
3222     var parent = element.parentNode;
3223     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3224   },
3225
3226   next: function(element) {
3227     return element.nextElementSibling;
3228   },
3229
3230   find: function(element, selector) {
3231     if (element.getElementsByTagName) {
3232       return element.getElementsByTagName(selector);
3233     } else {
3234       return [];
3235     }
3236   },
3237
3238   clone: jqLiteClone,
3239
3240   triggerHandler: function(element, event, extraParameters) {
3241
3242     var dummyEvent, eventFnsCopy, handlerArgs;
3243     var eventName = event.type || event;
3244     var expandoStore = jqLiteExpandoStore(element);
3245     var events = expandoStore && expandoStore.events;
3246     var eventFns = events && events[eventName];
3247
3248     if (eventFns) {
3249       // Create a dummy event to pass to the handlers
3250       dummyEvent = {
3251         preventDefault: function() { this.defaultPrevented = true; },
3252         isDefaultPrevented: function() { return this.defaultPrevented === true; },
3253         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3254         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3255         stopPropagation: noop,
3256         type: eventName,
3257         target: element
3258       };
3259
3260       // If a custom event was provided then extend our dummy event with it
3261       if (event.type) {
3262         dummyEvent = extend(dummyEvent, event);
3263       }
3264
3265       // Copy event handlers in case event handlers array is modified during execution.
3266       eventFnsCopy = shallowCopy(eventFns);
3267       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3268
3269       forEach(eventFnsCopy, function(fn) {
3270         if (!dummyEvent.isImmediatePropagationStopped()) {
3271           fn.apply(element, handlerArgs);
3272         }
3273       });
3274     }
3275   }
3276 }, function(fn, name) {
3277   /**
3278    * chaining functions
3279    */
3280   JQLite.prototype[name] = function(arg1, arg2, arg3) {
3281     var value;
3282
3283     for (var i = 0, ii = this.length; i < ii; i++) {
3284       if (isUndefined(value)) {
3285         value = fn(this[i], arg1, arg2, arg3);
3286         if (isDefined(value)) {
3287           // any function which returns a value needs to be wrapped
3288           value = jqLite(value);
3289         }
3290       } else {
3291         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3292       }
3293     }
3294     return isDefined(value) ? value : this;
3295   };
3296
3297   // bind legacy bind/unbind to on/off
3298   JQLite.prototype.bind = JQLite.prototype.on;
3299   JQLite.prototype.unbind = JQLite.prototype.off;
3300 });
3301
3302
3303 // Provider for private $$jqLite service
3304 function $$jqLiteProvider() {
3305   this.$get = function $$jqLite() {
3306     return extend(JQLite, {
3307       hasClass: function(node, classes) {
3308         if (node.attr) node = node[0];
3309         return jqLiteHasClass(node, classes);
3310       },
3311       addClass: function(node, classes) {
3312         if (node.attr) node = node[0];
3313         return jqLiteAddClass(node, classes);
3314       },
3315       removeClass: function(node, classes) {
3316         if (node.attr) node = node[0];
3317         return jqLiteRemoveClass(node, classes);
3318       }
3319     });
3320   };
3321 }
3322
3323 /**
3324  * Computes a hash of an 'obj'.
3325  * Hash of a:
3326  *  string is string
3327  *  number is number as string
3328  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3329  *         that is also assigned to the $$hashKey property of the object.
3330  *
3331  * @param obj
3332  * @returns {string} hash string such that the same input will have the same hash string.
3333  *         The resulting string key is in 'type:hashKey' format.
3334  */
3335 function hashKey(obj, nextUidFn) {
3336   var key = obj && obj.$$hashKey;
3337
3338   if (key) {
3339     if (typeof key === 'function') {
3340       key = obj.$$hashKey();
3341     }
3342     return key;
3343   }
3344
3345   var objType = typeof obj;
3346   if (objType == 'function' || (objType == 'object' && obj !== null)) {
3347     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3348   } else {
3349     key = objType + ':' + obj;
3350   }
3351
3352   return key;
3353 }
3354
3355 /**
3356  * HashMap which can use objects as keys
3357  */
3358 function HashMap(array, isolatedUid) {
3359   if (isolatedUid) {
3360     var uid = 0;
3361     this.nextUid = function() {
3362       return ++uid;
3363     };
3364   }
3365   forEach(array, this.put, this);
3366 }
3367 HashMap.prototype = {
3368   /**
3369    * Store key value pair
3370    * @param key key to store can be any type
3371    * @param value value to store can be any type
3372    */
3373   put: function(key, value) {
3374     this[hashKey(key, this.nextUid)] = value;
3375   },
3376
3377   /**
3378    * @param key
3379    * @returns {Object} the value for the key
3380    */
3381   get: function(key) {
3382     return this[hashKey(key, this.nextUid)];
3383   },
3384
3385   /**
3386    * Remove the key/value pair
3387    * @param key
3388    */
3389   remove: function(key) {
3390     var value = this[key = hashKey(key, this.nextUid)];
3391     delete this[key];
3392     return value;
3393   }
3394 };
3395
3396 /**
3397  * @ngdoc function
3398  * @module ng
3399  * @name angular.injector
3400  * @kind function
3401  *
3402  * @description
3403  * Creates an injector object that can be used for retrieving services as well as for
3404  * dependency injection (see {@link guide/di dependency injection}).
3405  *
3406  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3407  *     {@link angular.module}. The `ng` module must be explicitly added.
3408  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3409  *     disallows argument name annotation inference.
3410  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3411  *
3412  * @example
3413  * Typical usage
3414  * ```js
3415  *   // create an injector
3416  *   var $injector = angular.injector(['ng']);
3417  *
3418  *   // use the injector to kick off your application
3419  *   // use the type inference to auto inject arguments, or use implicit injection
3420  *   $injector.invoke(function($rootScope, $compile, $document) {
3421  *     $compile($document)($rootScope);
3422  *     $rootScope.$digest();
3423  *   });
3424  * ```
3425  *
3426  * Sometimes you want to get access to the injector of a currently running Angular app
3427  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3428  * application has been bootstrapped. You can do this using the extra `injector()` added
3429  * to JQuery/jqLite elements. See {@link angular.element}.
3430  *
3431  * *This is fairly rare but could be the case if a third party library is injecting the
3432  * markup.*
3433  *
3434  * In the following example a new block of HTML containing a `ng-controller`
3435  * directive is added to the end of the document body by JQuery. We then compile and link
3436  * it into the current AngularJS scope.
3437  *
3438  * ```js
3439  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3440  * $(document.body).append($div);
3441  *
3442  * angular.element(document).injector().invoke(function($compile) {
3443  *   var scope = angular.element($div).scope();
3444  *   $compile($div)(scope);
3445  * });
3446  * ```
3447  */
3448
3449
3450 /**
3451  * @ngdoc module
3452  * @name auto
3453  * @description
3454  *
3455  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3456  */
3457
3458 var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3459 var FN_ARG_SPLIT = /,/;
3460 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3461 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3462 var $injectorMinErr = minErr('$injector');
3463
3464 function anonFn(fn) {
3465   // For anonymous functions, showing at the very least the function signature can help in
3466   // debugging.
3467   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3468       args = fnText.match(FN_ARGS);
3469   if (args) {
3470     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3471   }
3472   return 'fn';
3473 }
3474
3475 function annotate(fn, strictDi, name) {
3476   var $inject,
3477       fnText,
3478       argDecl,
3479       last;
3480
3481   if (typeof fn === 'function') {
3482     if (!($inject = fn.$inject)) {
3483       $inject = [];
3484       if (fn.length) {
3485         if (strictDi) {
3486           if (!isString(name) || !name) {
3487             name = fn.name || anonFn(fn);
3488           }
3489           throw $injectorMinErr('strictdi',
3490             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3491         }
3492         fnText = fn.toString().replace(STRIP_COMMENTS, '');
3493         argDecl = fnText.match(FN_ARGS);
3494         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3495           arg.replace(FN_ARG, function(all, underscore, name) {
3496             $inject.push(name);
3497           });
3498         });
3499       }
3500       fn.$inject = $inject;
3501     }
3502   } else if (isArray(fn)) {
3503     last = fn.length - 1;
3504     assertArgFn(fn[last], 'fn');
3505     $inject = fn.slice(0, last);
3506   } else {
3507     assertArgFn(fn, 'fn', true);
3508   }
3509   return $inject;
3510 }
3511
3512 ///////////////////////////////////////
3513
3514 /**
3515  * @ngdoc service
3516  * @name $injector
3517  *
3518  * @description
3519  *
3520  * `$injector` is used to retrieve object instances as defined by
3521  * {@link auto.$provide provider}, instantiate types, invoke methods,
3522  * and load modules.
3523  *
3524  * The following always holds true:
3525  *
3526  * ```js
3527  *   var $injector = angular.injector();
3528  *   expect($injector.get('$injector')).toBe($injector);
3529  *   expect($injector.invoke(function($injector) {
3530  *     return $injector;
3531  *   })).toBe($injector);
3532  * ```
3533  *
3534  * # Injection Function Annotation
3535  *
3536  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3537  * following are all valid ways of annotating function with injection arguments and are equivalent.
3538  *
3539  * ```js
3540  *   // inferred (only works if code not minified/obfuscated)
3541  *   $injector.invoke(function(serviceA){});
3542  *
3543  *   // annotated
3544  *   function explicit(serviceA) {};
3545  *   explicit.$inject = ['serviceA'];
3546  *   $injector.invoke(explicit);
3547  *
3548  *   // inline
3549  *   $injector.invoke(['serviceA', function(serviceA){}]);
3550  * ```
3551  *
3552  * ## Inference
3553  *
3554  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3555  * can then be parsed and the function arguments can be extracted. This method of discovering
3556  * annotations is disallowed when the injector is in strict mode.
3557  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3558  * argument names.
3559  *
3560  * ## `$inject` Annotation
3561  * By adding an `$inject` property onto a function the injection parameters can be specified.
3562  *
3563  * ## Inline
3564  * As an array of injection names, where the last item in the array is the function to call.
3565  */
3566
3567 /**
3568  * @ngdoc method
3569  * @name $injector#get
3570  *
3571  * @description
3572  * Return an instance of the service.
3573  *
3574  * @param {string} name The name of the instance to retrieve.
3575  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3576  * @return {*} The instance.
3577  */
3578
3579 /**
3580  * @ngdoc method
3581  * @name $injector#invoke
3582  *
3583  * @description
3584  * Invoke the method and supply the method arguments from the `$injector`.
3585  *
3586  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3587  *   injected according to the {@link guide/di $inject Annotation} rules.
3588  * @param {Object=} self The `this` for the invoked method.
3589  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3590  *                         object first, before the `$injector` is consulted.
3591  * @returns {*} the value returned by the invoked `fn` function.
3592  */
3593
3594 /**
3595  * @ngdoc method
3596  * @name $injector#has
3597  *
3598  * @description
3599  * Allows the user to query if the particular service exists.
3600  *
3601  * @param {string} name Name of the service to query.
3602  * @returns {boolean} `true` if injector has given service.
3603  */
3604
3605 /**
3606  * @ngdoc method
3607  * @name $injector#instantiate
3608  * @description
3609  * Create a new instance of JS type. The method takes a constructor function, invokes the new
3610  * operator, and supplies all of the arguments to the constructor function as specified by the
3611  * constructor annotation.
3612  *
3613  * @param {Function} Type Annotated constructor function.
3614  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3615  * object first, before the `$injector` is consulted.
3616  * @returns {Object} new instance of `Type`.
3617  */
3618
3619 /**
3620  * @ngdoc method
3621  * @name $injector#annotate
3622  *
3623  * @description
3624  * Returns an array of service names which the function is requesting for injection. This API is
3625  * used by the injector to determine which services need to be injected into the function when the
3626  * function is invoked. There are three ways in which the function can be annotated with the needed
3627  * dependencies.
3628  *
3629  * # Argument names
3630  *
3631  * The simplest form is to extract the dependencies from the arguments of the function. This is done
3632  * by converting the function into a string using `toString()` method and extracting the argument
3633  * names.
3634  * ```js
3635  *   // Given
3636  *   function MyController($scope, $route) {
3637  *     // ...
3638  *   }
3639  *
3640  *   // Then
3641  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3642  * ```
3643  *
3644  * You can disallow this method by using strict injection mode.
3645  *
3646  * This method does not work with code minification / obfuscation. For this reason the following
3647  * annotation strategies are supported.
3648  *
3649  * # The `$inject` property
3650  *
3651  * If a function has an `$inject` property and its value is an array of strings, then the strings
3652  * represent names of services to be injected into the function.
3653  * ```js
3654  *   // Given
3655  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3656  *     // ...
3657  *   }
3658  *   // Define function dependencies
3659  *   MyController['$inject'] = ['$scope', '$route'];
3660  *
3661  *   // Then
3662  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3663  * ```
3664  *
3665  * # The array notation
3666  *
3667  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3668  * is very inconvenient. In these situations using the array notation to specify the dependencies in
3669  * a way that survives minification is a better choice:
3670  *
3671  * ```js
3672  *   // We wish to write this (not minification / obfuscation safe)
3673  *   injector.invoke(function($compile, $rootScope) {
3674  *     // ...
3675  *   });
3676  *
3677  *   // We are forced to write break inlining
3678  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3679  *     // ...
3680  *   };
3681  *   tmpFn.$inject = ['$compile', '$rootScope'];
3682  *   injector.invoke(tmpFn);
3683  *
3684  *   // To better support inline function the inline annotation is supported
3685  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3686  *     // ...
3687  *   }]);
3688  *
3689  *   // Therefore
3690  *   expect(injector.annotate(
3691  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3692  *    ).toEqual(['$compile', '$rootScope']);
3693  * ```
3694  *
3695  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3696  * be retrieved as described above.
3697  *
3698  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3699  *
3700  * @returns {Array.<string>} The names of the services which the function requires.
3701  */
3702
3703
3704
3705
3706 /**
3707  * @ngdoc service
3708  * @name $provide
3709  *
3710  * @description
3711  *
3712  * The {@link auto.$provide $provide} service has a number of methods for registering components
3713  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3714  * {@link angular.Module}.
3715  *
3716  * An Angular **service** is a singleton object created by a **service factory**.  These **service
3717  * factories** are functions which, in turn, are created by a **service provider**.
3718  * The **service providers** are constructor functions. When instantiated they must contain a
3719  * property called `$get`, which holds the **service factory** function.
3720  *
3721  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3722  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3723  * function to get the instance of the **service**.
3724  *
3725  * Often services have no configuration options and there is no need to add methods to the service
3726  * provider.  The provider will be no more than a constructor function with a `$get` property. For
3727  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3728  * services without specifying a provider.
3729  *
3730  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3731  *     {@link auto.$injector $injector}
3732  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3733  *     providers and services.
3734  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3735  *     services, not providers.
3736  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3737  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3738  *     given factory function.
3739  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3740  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3741  *      a new object using the given constructor function.
3742  *
3743  * See the individual methods for more information and examples.
3744  */
3745
3746 /**
3747  * @ngdoc method
3748  * @name $provide#provider
3749  * @description
3750  *
3751  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3752  * are constructor functions, whose instances are responsible for "providing" a factory for a
3753  * service.
3754  *
3755  * Service provider names start with the name of the service they provide followed by `Provider`.
3756  * For example, the {@link ng.$log $log} service has a provider called
3757  * {@link ng.$logProvider $logProvider}.
3758  *
3759  * Service provider objects can have additional methods which allow configuration of the provider
3760  * and its service. Importantly, you can configure what kind of service is created by the `$get`
3761  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3762  * method {@link ng.$logProvider#debugEnabled debugEnabled}
3763  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3764  * console or not.
3765  *
3766  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3767                         'Provider'` key.
3768  * @param {(Object|function())} provider If the provider is:
3769  *
3770  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3771  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3772  *   - `Constructor`: a new instance of the provider will be created using
3773  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3774  *
3775  * @returns {Object} registered provider instance
3776
3777  * @example
3778  *
3779  * The following example shows how to create a simple event tracking service and register it using
3780  * {@link auto.$provide#provider $provide.provider()}.
3781  *
3782  * ```js
3783  *  // Define the eventTracker provider
3784  *  function EventTrackerProvider() {
3785  *    var trackingUrl = '/track';
3786  *
3787  *    // A provider method for configuring where the tracked events should been saved
3788  *    this.setTrackingUrl = function(url) {
3789  *      trackingUrl = url;
3790  *    };
3791  *
3792  *    // The service factory function
3793  *    this.$get = ['$http', function($http) {
3794  *      var trackedEvents = {};
3795  *      return {
3796  *        // Call this to track an event
3797  *        event: function(event) {
3798  *          var count = trackedEvents[event] || 0;
3799  *          count += 1;
3800  *          trackedEvents[event] = count;
3801  *          return count;
3802  *        },
3803  *        // Call this to save the tracked events to the trackingUrl
3804  *        save: function() {
3805  *          $http.post(trackingUrl, trackedEvents);
3806  *        }
3807  *      };
3808  *    }];
3809  *  }
3810  *
3811  *  describe('eventTracker', function() {
3812  *    var postSpy;
3813  *
3814  *    beforeEach(module(function($provide) {
3815  *      // Register the eventTracker provider
3816  *      $provide.provider('eventTracker', EventTrackerProvider);
3817  *    }));
3818  *
3819  *    beforeEach(module(function(eventTrackerProvider) {
3820  *      // Configure eventTracker provider
3821  *      eventTrackerProvider.setTrackingUrl('/custom-track');
3822  *    }));
3823  *
3824  *    it('tracks events', inject(function(eventTracker) {
3825  *      expect(eventTracker.event('login')).toEqual(1);
3826  *      expect(eventTracker.event('login')).toEqual(2);
3827  *    }));
3828  *
3829  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3830  *      postSpy = spyOn($http, 'post');
3831  *      eventTracker.event('login');
3832  *      eventTracker.save();
3833  *      expect(postSpy).toHaveBeenCalled();
3834  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3835  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3836  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3837  *    }));
3838  *  });
3839  * ```
3840  */
3841
3842 /**
3843  * @ngdoc method
3844  * @name $provide#factory
3845  * @description
3846  *
3847  * Register a **service factory**, which will be called to return the service instance.
3848  * This is short for registering a service where its provider consists of only a `$get` property,
3849  * which is the given service factory function.
3850  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3851  * configure your service in a provider.
3852  *
3853  * @param {string} name The name of the instance.
3854  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
3855  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
3856  * @returns {Object} registered provider instance
3857  *
3858  * @example
3859  * Here is an example of registering a service
3860  * ```js
3861  *   $provide.factory('ping', ['$http', function($http) {
3862  *     return function ping() {
3863  *       return $http.send('/ping');
3864  *     };
3865  *   }]);
3866  * ```
3867  * You would then inject and use this service like this:
3868  * ```js
3869  *   someModule.controller('Ctrl', ['ping', function(ping) {
3870  *     ping();
3871  *   }]);
3872  * ```
3873  */
3874
3875
3876 /**
3877  * @ngdoc method
3878  * @name $provide#service
3879  * @description
3880  *
3881  * Register a **service constructor**, which will be invoked with `new` to create the service
3882  * instance.
3883  * This is short for registering a service where its provider's `$get` property is the service
3884  * constructor function that will be used to instantiate the service instance.
3885  *
3886  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3887  * as a type/class.
3888  *
3889  * @param {string} name The name of the instance.
3890  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
3891  *     that will be instantiated.
3892  * @returns {Object} registered provider instance
3893  *
3894  * @example
3895  * Here is an example of registering a service using
3896  * {@link auto.$provide#service $provide.service(class)}.
3897  * ```js
3898  *   var Ping = function($http) {
3899  *     this.$http = $http;
3900  *   };
3901  *
3902  *   Ping.$inject = ['$http'];
3903  *
3904  *   Ping.prototype.send = function() {
3905  *     return this.$http.get('/ping');
3906  *   };
3907  *   $provide.service('ping', Ping);
3908  * ```
3909  * You would then inject and use this service like this:
3910  * ```js
3911  *   someModule.controller('Ctrl', ['ping', function(ping) {
3912  *     ping.send();
3913  *   }]);
3914  * ```
3915  */
3916
3917
3918 /**
3919  * @ngdoc method
3920  * @name $provide#value
3921  * @description
3922  *
3923  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3924  * number, an array, an object or a function.  This is short for registering a service where its
3925  * provider's `$get` property is a factory function that takes no arguments and returns the **value
3926  * service**.
3927  *
3928  * Value services are similar to constant services, except that they cannot be injected into a
3929  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3930  * an Angular
3931  * {@link auto.$provide#decorator decorator}.
3932  *
3933  * @param {string} name The name of the instance.
3934  * @param {*} value The value.
3935  * @returns {Object} registered provider instance
3936  *
3937  * @example
3938  * Here are some examples of creating value services.
3939  * ```js
3940  *   $provide.value('ADMIN_USER', 'admin');
3941  *
3942  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3943  *
3944  *   $provide.value('halfOf', function(value) {
3945  *     return value / 2;
3946  *   });
3947  * ```
3948  */
3949
3950
3951 /**
3952  * @ngdoc method
3953  * @name $provide#constant
3954  * @description
3955  *
3956  * Register a **constant service**, such as a string, a number, an array, an object or a function,
3957  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3958  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3959  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3960  *
3961  * @param {string} name The name of the constant.
3962  * @param {*} value The constant value.
3963  * @returns {Object} registered instance
3964  *
3965  * @example
3966  * Here a some examples of creating constants:
3967  * ```js
3968  *   $provide.constant('SHARD_HEIGHT', 306);
3969  *
3970  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3971  *
3972  *   $provide.constant('double', function(value) {
3973  *     return value * 2;
3974  *   });
3975  * ```
3976  */
3977
3978
3979 /**
3980  * @ngdoc method
3981  * @name $provide#decorator
3982  * @description
3983  *
3984  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3985  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3986  * service. The object returned by the decorator may be the original service, or a new service
3987  * object which replaces or wraps and delegates to the original service.
3988  *
3989  * @param {string} name The name of the service to decorate.
3990  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
3991  *    instantiated and should return the decorated service instance. The function is called using
3992  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3993  *    Local injection arguments:
3994  *
3995  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3996  *      decorated or delegated to.
3997  *
3998  * @example
3999  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4000  * calls to {@link ng.$log#error $log.warn()}.
4001  * ```js
4002  *   $provide.decorator('$log', ['$delegate', function($delegate) {
4003  *     $delegate.warn = $delegate.error;
4004  *     return $delegate;
4005  *   }]);
4006  * ```
4007  */
4008
4009
4010 function createInjector(modulesToLoad, strictDi) {
4011   strictDi = (strictDi === true);
4012   var INSTANTIATING = {},
4013       providerSuffix = 'Provider',
4014       path = [],
4015       loadedModules = new HashMap([], true),
4016       providerCache = {
4017         $provide: {
4018             provider: supportObject(provider),
4019             factory: supportObject(factory),
4020             service: supportObject(service),
4021             value: supportObject(value),
4022             constant: supportObject(constant),
4023             decorator: decorator
4024           }
4025       },
4026       providerInjector = (providerCache.$injector =
4027           createInternalInjector(providerCache, function(serviceName, caller) {
4028             if (angular.isString(caller)) {
4029               path.push(caller);
4030             }
4031             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4032           })),
4033       instanceCache = {},
4034       instanceInjector = (instanceCache.$injector =
4035           createInternalInjector(instanceCache, function(serviceName, caller) {
4036             var provider = providerInjector.get(serviceName + providerSuffix, caller);
4037             return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4038           }));
4039
4040
4041   forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
4042
4043   return instanceInjector;
4044
4045   ////////////////////////////////////
4046   // $provider
4047   ////////////////////////////////////
4048
4049   function supportObject(delegate) {
4050     return function(key, value) {
4051       if (isObject(key)) {
4052         forEach(key, reverseParams(delegate));
4053       } else {
4054         return delegate(key, value);
4055       }
4056     };
4057   }
4058
4059   function provider(name, provider_) {
4060     assertNotHasOwnProperty(name, 'service');
4061     if (isFunction(provider_) || isArray(provider_)) {
4062       provider_ = providerInjector.instantiate(provider_);
4063     }
4064     if (!provider_.$get) {
4065       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4066     }
4067     return providerCache[name + providerSuffix] = provider_;
4068   }
4069
4070   function enforceReturnValue(name, factory) {
4071     return function enforcedReturnValue() {
4072       var result = instanceInjector.invoke(factory, this);
4073       if (isUndefined(result)) {
4074         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4075       }
4076       return result;
4077     };
4078   }
4079
4080   function factory(name, factoryFn, enforce) {
4081     return provider(name, {
4082       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4083     });
4084   }
4085
4086   function service(name, constructor) {
4087     return factory(name, ['$injector', function($injector) {
4088       return $injector.instantiate(constructor);
4089     }]);
4090   }
4091
4092   function value(name, val) { return factory(name, valueFn(val), false); }
4093
4094   function constant(name, value) {
4095     assertNotHasOwnProperty(name, 'constant');
4096     providerCache[name] = value;
4097     instanceCache[name] = value;
4098   }
4099
4100   function decorator(serviceName, decorFn) {
4101     var origProvider = providerInjector.get(serviceName + providerSuffix),
4102         orig$get = origProvider.$get;
4103
4104     origProvider.$get = function() {
4105       var origInstance = instanceInjector.invoke(orig$get, origProvider);
4106       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4107     };
4108   }
4109
4110   ////////////////////////////////////
4111   // Module Loading
4112   ////////////////////////////////////
4113   function loadModules(modulesToLoad) {
4114     var runBlocks = [], moduleFn;
4115     forEach(modulesToLoad, function(module) {
4116       if (loadedModules.get(module)) return;
4117       loadedModules.put(module, true);
4118
4119       function runInvokeQueue(queue) {
4120         var i, ii;
4121         for (i = 0, ii = queue.length; i < ii; i++) {
4122           var invokeArgs = queue[i],
4123               provider = providerInjector.get(invokeArgs[0]);
4124
4125           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4126         }
4127       }
4128
4129       try {
4130         if (isString(module)) {
4131           moduleFn = angularModule(module);
4132           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4133           runInvokeQueue(moduleFn._invokeQueue);
4134           runInvokeQueue(moduleFn._configBlocks);
4135         } else if (isFunction(module)) {
4136             runBlocks.push(providerInjector.invoke(module));
4137         } else if (isArray(module)) {
4138             runBlocks.push(providerInjector.invoke(module));
4139         } else {
4140           assertArgFn(module, 'module');
4141         }
4142       } catch (e) {
4143         if (isArray(module)) {
4144           module = module[module.length - 1];
4145         }
4146         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4147           // Safari & FF's stack traces don't contain error.message content
4148           // unlike those of Chrome and IE
4149           // So if stack doesn't contain message, we create a new string that contains both.
4150           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4151           /* jshint -W022 */
4152           e = e.message + '\n' + e.stack;
4153         }
4154         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4155                   module, e.stack || e.message || e);
4156       }
4157     });
4158     return runBlocks;
4159   }
4160
4161   ////////////////////////////////////
4162   // internal Injector
4163   ////////////////////////////////////
4164
4165   function createInternalInjector(cache, factory) {
4166
4167     function getService(serviceName, caller) {
4168       if (cache.hasOwnProperty(serviceName)) {
4169         if (cache[serviceName] === INSTANTIATING) {
4170           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4171                     serviceName + ' <- ' + path.join(' <- '));
4172         }
4173         return cache[serviceName];
4174       } else {
4175         try {
4176           path.unshift(serviceName);
4177           cache[serviceName] = INSTANTIATING;
4178           return cache[serviceName] = factory(serviceName, caller);
4179         } catch (err) {
4180           if (cache[serviceName] === INSTANTIATING) {
4181             delete cache[serviceName];
4182           }
4183           throw err;
4184         } finally {
4185           path.shift();
4186         }
4187       }
4188     }
4189
4190     function invoke(fn, self, locals, serviceName) {
4191       if (typeof locals === 'string') {
4192         serviceName = locals;
4193         locals = null;
4194       }
4195
4196       var args = [],
4197           $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4198           length, i,
4199           key;
4200
4201       for (i = 0, length = $inject.length; i < length; i++) {
4202         key = $inject[i];
4203         if (typeof key !== 'string') {
4204           throw $injectorMinErr('itkn',
4205                   'Incorrect injection token! Expected service name as string, got {0}', key);
4206         }
4207         args.push(
4208           locals && locals.hasOwnProperty(key)
4209           ? locals[key]
4210           : getService(key, serviceName)
4211         );
4212       }
4213       if (isArray(fn)) {
4214         fn = fn[length];
4215       }
4216
4217       // http://jsperf.com/angularjs-invoke-apply-vs-switch
4218       // #5388
4219       return fn.apply(self, args);
4220     }
4221
4222     function instantiate(Type, locals, serviceName) {
4223       // Check if Type is annotated and use just the given function at n-1 as parameter
4224       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4225       // Object creation: http://jsperf.com/create-constructor/2
4226       var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4227       var returnedValue = invoke(Type, instance, locals, serviceName);
4228
4229       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4230     }
4231
4232     return {
4233       invoke: invoke,
4234       instantiate: instantiate,
4235       get: getService,
4236       annotate: createInjector.$$annotate,
4237       has: function(name) {
4238         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4239       }
4240     };
4241   }
4242 }
4243
4244 createInjector.$$annotate = annotate;
4245
4246 /**
4247  * @ngdoc provider
4248  * @name $anchorScrollProvider
4249  *
4250  * @description
4251  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4252  * {@link ng.$location#hash $location.hash()} changes.
4253  */
4254 function $AnchorScrollProvider() {
4255
4256   var autoScrollingEnabled = true;
4257
4258   /**
4259    * @ngdoc method
4260    * @name $anchorScrollProvider#disableAutoScrolling
4261    *
4262    * @description
4263    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4264    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4265    * Use this method to disable automatic scrolling.
4266    *
4267    * If automatic scrolling is disabled, one must explicitly call
4268    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4269    * current hash.
4270    */
4271   this.disableAutoScrolling = function() {
4272     autoScrollingEnabled = false;
4273   };
4274
4275   /**
4276    * @ngdoc service
4277    * @name $anchorScroll
4278    * @kind function
4279    * @requires $window
4280    * @requires $location
4281    * @requires $rootScope
4282    *
4283    * @description
4284    * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
4285    * scrolls to the related element, according to the rules specified in the
4286    * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4287    *
4288    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4289    * match any anchor whenever it changes. This can be disabled by calling
4290    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4291    *
4292    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4293    * vertical scroll-offset (either fixed or dynamic).
4294    *
4295    * @property {(number|function|jqLite)} yOffset
4296    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4297    * positioned elements at the top of the page, such as navbars, headers etc.
4298    *
4299    * `yOffset` can be specified in various ways:
4300    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4301    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4302    *   a number representing the offset (in pixels).<br /><br />
4303    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4304    *   the top of the page to the element's bottom will be used as offset.<br />
4305    *   **Note**: The element will be taken into account only as long as its `position` is set to
4306    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4307    *   their height and/or positioning according to the viewport's size.
4308    *
4309    * <br />
4310    * <div class="alert alert-warning">
4311    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4312    * not some child element.
4313    * </div>
4314    *
4315    * @example
4316      <example module="anchorScrollExample">
4317        <file name="index.html">
4318          <div id="scrollArea" ng-controller="ScrollController">
4319            <a ng-click="gotoBottom()">Go to bottom</a>
4320            <a id="bottom"></a> You're at the bottom!
4321          </div>
4322        </file>
4323        <file name="script.js">
4324          angular.module('anchorScrollExample', [])
4325            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4326              function ($scope, $location, $anchorScroll) {
4327                $scope.gotoBottom = function() {
4328                  // set the location.hash to the id of
4329                  // the element you wish to scroll to.
4330                  $location.hash('bottom');
4331
4332                  // call $anchorScroll()
4333                  $anchorScroll();
4334                };
4335              }]);
4336        </file>
4337        <file name="style.css">
4338          #scrollArea {
4339            height: 280px;
4340            overflow: auto;
4341          }
4342
4343          #bottom {
4344            display: block;
4345            margin-top: 2000px;
4346          }
4347        </file>
4348      </example>
4349    *
4350    * <hr />
4351    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4352    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4353    *
4354    * @example
4355      <example module="anchorScrollOffsetExample">
4356        <file name="index.html">
4357          <div class="fixed-header" ng-controller="headerCtrl">
4358            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4359              Go to anchor {{x}}
4360            </a>
4361          </div>
4362          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4363            Anchor {{x}} of 5
4364          </div>
4365        </file>
4366        <file name="script.js">
4367          angular.module('anchorScrollOffsetExample', [])
4368            .run(['$anchorScroll', function($anchorScroll) {
4369              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4370            }])
4371            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4372              function ($anchorScroll, $location, $scope) {
4373                $scope.gotoAnchor = function(x) {
4374                  var newHash = 'anchor' + x;
4375                  if ($location.hash() !== newHash) {
4376                    // set the $location.hash to `newHash` and
4377                    // $anchorScroll will automatically scroll to it
4378                    $location.hash('anchor' + x);
4379                  } else {
4380                    // call $anchorScroll() explicitly,
4381                    // since $location.hash hasn't changed
4382                    $anchorScroll();
4383                  }
4384                };
4385              }
4386            ]);
4387        </file>
4388        <file name="style.css">
4389          body {
4390            padding-top: 50px;
4391          }
4392
4393          .anchor {
4394            border: 2px dashed DarkOrchid;
4395            padding: 10px 10px 200px 10px;
4396          }
4397
4398          .fixed-header {
4399            background-color: rgba(0, 0, 0, 0.2);
4400            height: 50px;
4401            position: fixed;
4402            top: 0; left: 0; right: 0;
4403          }
4404
4405          .fixed-header > a {
4406            display: inline-block;
4407            margin: 5px 15px;
4408          }
4409        </file>
4410      </example>
4411    */
4412   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4413     var document = $window.document;
4414
4415     // Helper function to get first anchor from a NodeList
4416     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4417     //  and working in all supported browsers.)
4418     function getFirstAnchor(list) {
4419       var result = null;
4420       Array.prototype.some.call(list, function(element) {
4421         if (nodeName_(element) === 'a') {
4422           result = element;
4423           return true;
4424         }
4425       });
4426       return result;
4427     }
4428
4429     function getYOffset() {
4430
4431       var offset = scroll.yOffset;
4432
4433       if (isFunction(offset)) {
4434         offset = offset();
4435       } else if (isElement(offset)) {
4436         var elem = offset[0];
4437         var style = $window.getComputedStyle(elem);
4438         if (style.position !== 'fixed') {
4439           offset = 0;
4440         } else {
4441           offset = elem.getBoundingClientRect().bottom;
4442         }
4443       } else if (!isNumber(offset)) {
4444         offset = 0;
4445       }
4446
4447       return offset;
4448     }
4449
4450     function scrollTo(elem) {
4451       if (elem) {
4452         elem.scrollIntoView();
4453
4454         var offset = getYOffset();
4455
4456         if (offset) {
4457           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4458           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4459           // top of the viewport.
4460           //
4461           // IF the number of pixels from the top of `elem` to the end of the page's content is less
4462           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4463           // way down the page.
4464           //
4465           // This is often the case for elements near the bottom of the page.
4466           //
4467           // In such cases we do not need to scroll the whole `offset` up, just the difference between
4468           // the top of the element and the offset, which is enough to align the top of `elem` at the
4469           // desired position.
4470           var elemTop = elem.getBoundingClientRect().top;
4471           $window.scrollBy(0, elemTop - offset);
4472         }
4473       } else {
4474         $window.scrollTo(0, 0);
4475       }
4476     }
4477
4478     function scroll() {
4479       var hash = $location.hash(), elm;
4480
4481       // empty hash, scroll to the top of the page
4482       if (!hash) scrollTo(null);
4483
4484       // element with given id
4485       else if ((elm = document.getElementById(hash))) scrollTo(elm);
4486
4487       // first anchor with given name :-D
4488       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4489
4490       // no element and hash == 'top', scroll to the top of the page
4491       else if (hash === 'top') scrollTo(null);
4492     }
4493
4494     // does not scroll when user clicks on anchor link that is currently on
4495     // (no url change, no $location.hash() change), browser native does scroll
4496     if (autoScrollingEnabled) {
4497       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4498         function autoScrollWatchAction(newVal, oldVal) {
4499           // skip the initial scroll if $location.hash is empty
4500           if (newVal === oldVal && newVal === '') return;
4501
4502           jqLiteDocumentLoaded(function() {
4503             $rootScope.$evalAsync(scroll);
4504           });
4505         });
4506     }
4507
4508     return scroll;
4509   }];
4510 }
4511
4512 var $animateMinErr = minErr('$animate');
4513
4514 /**
4515  * @ngdoc provider
4516  * @name $animateProvider
4517  *
4518  * @description
4519  * Default implementation of $animate that doesn't perform any animations, instead just
4520  * synchronously performs DOM
4521  * updates and calls done() callbacks.
4522  *
4523  * In order to enable animations the ngAnimate module has to be loaded.
4524  *
4525  * To see the functional implementation check out src/ngAnimate/animate.js
4526  */
4527 var $AnimateProvider = ['$provide', function($provide) {
4528
4529
4530   this.$$selectors = {};
4531
4532
4533   /**
4534    * @ngdoc method
4535    * @name $animateProvider#register
4536    *
4537    * @description
4538    * Registers a new injectable animation factory function. The factory function produces the
4539    * animation object which contains callback functions for each event that is expected to be
4540    * animated.
4541    *
4542    *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4543    *   must be called once the element animation is complete. If a function is returned then the
4544    *   animation service will use this function to cancel the animation whenever a cancel event is
4545    *   triggered.
4546    *
4547    *
4548    * ```js
4549    *   return {
4550      *     eventFn : function(element, done) {
4551      *       //code to run the animation
4552      *       //once complete, then run done()
4553      *       return function cancellationFunction() {
4554      *         //code to cancel the animation
4555      *       }
4556      *     }
4557      *   }
4558    * ```
4559    *
4560    * @param {string} name The name of the animation.
4561    * @param {Function} factory The factory function that will be executed to return the animation
4562    *                           object.
4563    */
4564   this.register = function(name, factory) {
4565     var key = name + '-animation';
4566     if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4567         "Expecting class selector starting with '.' got '{0}'.", name);
4568     this.$$selectors[name.substr(1)] = key;
4569     $provide.factory(key, factory);
4570   };
4571
4572   /**
4573    * @ngdoc method
4574    * @name $animateProvider#classNameFilter
4575    *
4576    * @description
4577    * Sets and/or returns the CSS class regular expression that is checked when performing
4578    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4579    * therefore enable $animate to attempt to perform an animation on any element.
4580    * When setting the classNameFilter value, animations will only be performed on elements
4581    * that successfully match the filter expression. This in turn can boost performance
4582    * for low-powered devices as well as applications containing a lot of structural operations.
4583    * @param {RegExp=} expression The className expression which will be checked against all animations
4584    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4585    */
4586   this.classNameFilter = function(expression) {
4587     if (arguments.length === 1) {
4588       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4589     }
4590     return this.$$classNameFilter;
4591   };
4592
4593   this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) {
4594
4595     var currentDefer;
4596
4597     function runAnimationPostDigest(fn) {
4598       var cancelFn, defer = $$q.defer();
4599       defer.promise.$$cancelFn = function ngAnimateMaybeCancel() {
4600         cancelFn && cancelFn();
4601       };
4602
4603       $rootScope.$$postDigest(function ngAnimatePostDigest() {
4604         cancelFn = fn(function ngAnimateNotifyComplete() {
4605           defer.resolve();
4606         });
4607       });
4608
4609       return defer.promise;
4610     }
4611
4612     function resolveElementClasses(element, classes) {
4613       var toAdd = [], toRemove = [];
4614
4615       var hasClasses = createMap();
4616       forEach((element.attr('class') || '').split(/\s+/), function(className) {
4617         hasClasses[className] = true;
4618       });
4619
4620       forEach(classes, function(status, className) {
4621         var hasClass = hasClasses[className];
4622
4623         // If the most recent class manipulation (via $animate) was to remove the class, and the
4624         // element currently has the class, the class is scheduled for removal. Otherwise, if
4625         // the most recent class manipulation (via $animate) was to add the class, and the
4626         // element does not currently have the class, the class is scheduled to be added.
4627         if (status === false && hasClass) {
4628           toRemove.push(className);
4629         } else if (status === true && !hasClass) {
4630           toAdd.push(className);
4631         }
4632       });
4633
4634       return (toAdd.length + toRemove.length) > 0 &&
4635         [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
4636     }
4637
4638     function cachedClassManipulation(cache, classes, op) {
4639       for (var i=0, ii = classes.length; i < ii; ++i) {
4640         var className = classes[i];
4641         cache[className] = op;
4642       }
4643     }
4644
4645     function asyncPromise() {
4646       // only serve one instance of a promise in order to save CPU cycles
4647       if (!currentDefer) {
4648         currentDefer = $$q.defer();
4649         $$asyncCallback(function() {
4650           currentDefer.resolve();
4651           currentDefer = null;
4652         });
4653       }
4654       return currentDefer.promise;
4655     }
4656
4657     function applyStyles(element, options) {
4658       if (angular.isObject(options)) {
4659         var styles = extend(options.from || {}, options.to || {});
4660         element.css(styles);
4661       }
4662     }
4663
4664     /**
4665      *
4666      * @ngdoc service
4667      * @name $animate
4668      * @description The $animate service provides rudimentary DOM manipulation functions to
4669      * insert, remove and move elements within the DOM, as well as adding and removing classes.
4670      * This service is the core service used by the ngAnimate $animator service which provides
4671      * high-level animation hooks for CSS and JavaScript.
4672      *
4673      * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4674      * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4675      * manipulation operations.
4676      *
4677      * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4678      * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4679      * page}.
4680      */
4681     return {
4682       animate: function(element, from, to) {
4683         applyStyles(element, { from: from, to: to });
4684         return asyncPromise();
4685       },
4686
4687       /**
4688        *
4689        * @ngdoc method
4690        * @name $animate#enter
4691        * @kind function
4692        * @description Inserts the element into the DOM either after the `after` element or
4693        * as the first child within the `parent` element. When the function is called a promise
4694        * is returned that will be resolved at a later time.
4695        * @param {DOMElement} element the element which will be inserted into the DOM
4696        * @param {DOMElement} parent the parent element which will append the element as
4697        *   a child (if the after element is not present)
4698        * @param {DOMElement} after the sibling element which will append the element
4699        *   after itself
4700        * @param {object=} options an optional collection of styles that will be applied to the element.
4701        * @return {Promise} the animation callback promise
4702        */
4703       enter: function(element, parent, after, options) {
4704         applyStyles(element, options);
4705         after ? after.after(element)
4706               : parent.prepend(element);
4707         return asyncPromise();
4708       },
4709
4710       /**
4711        *
4712        * @ngdoc method
4713        * @name $animate#leave
4714        * @kind function
4715        * @description Removes the element from the DOM. When the function is called a promise
4716        * is returned that will be resolved at a later time.
4717        * @param {DOMElement} element the element which will be removed from the DOM
4718        * @param {object=} options an optional collection of options that will be applied to the element.
4719        * @return {Promise} the animation callback promise
4720        */
4721       leave: function(element, options) {
4722         applyStyles(element, options);
4723         element.remove();
4724         return asyncPromise();
4725       },
4726
4727       /**
4728        *
4729        * @ngdoc method
4730        * @name $animate#move
4731        * @kind function
4732        * @description Moves the position of the provided element within the DOM to be placed
4733        * either after the `after` element or inside of the `parent` element. When the function
4734        * is called a promise is returned that will be resolved at a later time.
4735        *
4736        * @param {DOMElement} element the element which will be moved around within the
4737        *   DOM
4738        * @param {DOMElement} parent the parent element where the element will be
4739        *   inserted into (if the after element is not present)
4740        * @param {DOMElement} after the sibling element where the element will be
4741        *   positioned next to
4742        * @param {object=} options an optional collection of options that will be applied to the element.
4743        * @return {Promise} the animation callback promise
4744        */
4745       move: function(element, parent, after, options) {
4746         // Do not remove element before insert. Removing will cause data associated with the
4747         // element to be dropped. Insert will implicitly do the remove.
4748         return this.enter(element, parent, after, options);
4749       },
4750
4751       /**
4752        *
4753        * @ngdoc method
4754        * @name $animate#addClass
4755        * @kind function
4756        * @description Adds the provided className CSS class value to the provided element.
4757        * When the function is called a promise is returned that will be resolved at a later time.
4758        * @param {DOMElement} element the element which will have the className value
4759        *   added to it
4760        * @param {string} className the CSS class which will be added to the element
4761        * @param {object=} options an optional collection of options that will be applied to the element.
4762        * @return {Promise} the animation callback promise
4763        */
4764       addClass: function(element, className, options) {
4765         return this.setClass(element, className, [], options);
4766       },
4767
4768       $$addClassImmediately: function(element, className, options) {
4769         element = jqLite(element);
4770         className = !isString(className)
4771                         ? (isArray(className) ? className.join(' ') : '')
4772                         : className;
4773         forEach(element, function(element) {
4774           jqLiteAddClass(element, className);
4775         });
4776         applyStyles(element, options);
4777         return asyncPromise();
4778       },
4779
4780       /**
4781        *
4782        * @ngdoc method
4783        * @name $animate#removeClass
4784        * @kind function
4785        * @description Removes the provided className CSS class value from the provided element.
4786        * When the function is called a promise is returned that will be resolved at a later time.
4787        * @param {DOMElement} element the element which will have the className value
4788        *   removed from it
4789        * @param {string} className the CSS class which will be removed from the element
4790        * @param {object=} options an optional collection of options that will be applied to the element.
4791        * @return {Promise} the animation callback promise
4792        */
4793       removeClass: function(element, className, options) {
4794         return this.setClass(element, [], className, options);
4795       },
4796
4797       $$removeClassImmediately: function(element, className, options) {
4798         element = jqLite(element);
4799         className = !isString(className)
4800                         ? (isArray(className) ? className.join(' ') : '')
4801                         : className;
4802         forEach(element, function(element) {
4803           jqLiteRemoveClass(element, className);
4804         });
4805         applyStyles(element, options);
4806         return asyncPromise();
4807       },
4808
4809       /**
4810        *
4811        * @ngdoc method
4812        * @name $animate#setClass
4813        * @kind function
4814        * @description Adds and/or removes the given CSS classes to and from the element.
4815        * When the function is called a promise is returned that will be resolved at a later time.
4816        * @param {DOMElement} element the element which will have its CSS classes changed
4817        *   removed from it
4818        * @param {string} add the CSS classes which will be added to the element
4819        * @param {string} remove the CSS class which will be removed from the element
4820        * @param {object=} options an optional collection of options that will be applied to the element.
4821        * @return {Promise} the animation callback promise
4822        */
4823       setClass: function(element, add, remove, options) {
4824         var self = this;
4825         var STORAGE_KEY = '$$animateClasses';
4826         var createdCache = false;
4827         element = jqLite(element);
4828
4829         var cache = element.data(STORAGE_KEY);
4830         if (!cache) {
4831           cache = {
4832             classes: {},
4833             options: options
4834           };
4835           createdCache = true;
4836         } else if (options && cache.options) {
4837           cache.options = angular.extend(cache.options || {}, options);
4838         }
4839
4840         var classes = cache.classes;
4841
4842         add = isArray(add) ? add : add.split(' ');
4843         remove = isArray(remove) ? remove : remove.split(' ');
4844         cachedClassManipulation(classes, add, true);
4845         cachedClassManipulation(classes, remove, false);
4846
4847         if (createdCache) {
4848           cache.promise = runAnimationPostDigest(function(done) {
4849             var cache = element.data(STORAGE_KEY);
4850             element.removeData(STORAGE_KEY);
4851
4852             // in the event that the element is removed before postDigest
4853             // is run then the cache will be undefined and there will be
4854             // no need anymore to add or remove and of the element classes
4855             if (cache) {
4856               var classes = resolveElementClasses(element, cache.classes);
4857               if (classes) {
4858                 self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
4859               }
4860             }
4861
4862             done();
4863           });
4864           element.data(STORAGE_KEY, cache);
4865         }
4866
4867         return cache.promise;
4868       },
4869
4870       $$setClassImmediately: function(element, add, remove, options) {
4871         add && this.$$addClassImmediately(element, add);
4872         remove && this.$$removeClassImmediately(element, remove);
4873         applyStyles(element, options);
4874         return asyncPromise();
4875       },
4876
4877       enabled: noop,
4878       cancel: noop
4879     };
4880   }];
4881 }];
4882
4883 function $$AsyncCallbackProvider() {
4884   this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4885     return $$rAF.supported
4886       ? function(fn) { return $$rAF(fn); }
4887       : function(fn) {
4888         return $timeout(fn, 0, false);
4889       };
4890   }];
4891 }
4892
4893 /* global stripHash: true */
4894
4895 /**
4896  * ! This is a private undocumented service !
4897  *
4898  * @name $browser
4899  * @requires $log
4900  * @description
4901  * This object has two goals:
4902  *
4903  * - hide all the global state in the browser caused by the window object
4904  * - abstract away all the browser specific features and inconsistencies
4905  *
4906  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4907  * service, which can be used for convenient testing of the application without the interaction with
4908  * the real browser apis.
4909  */
4910 /**
4911  * @param {object} window The global window object.
4912  * @param {object} document jQuery wrapped document.
4913  * @param {object} $log window.console or an object with the same interface.
4914  * @param {object} $sniffer $sniffer service
4915  */
4916 function Browser(window, document, $log, $sniffer) {
4917   var self = this,
4918       rawDocument = document[0],
4919       location = window.location,
4920       history = window.history,
4921       setTimeout = window.setTimeout,
4922       clearTimeout = window.clearTimeout,
4923       pendingDeferIds = {};
4924
4925   self.isMock = false;
4926
4927   var outstandingRequestCount = 0;
4928   var outstandingRequestCallbacks = [];
4929
4930   // TODO(vojta): remove this temporary api
4931   self.$$completeOutstandingRequest = completeOutstandingRequest;
4932   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4933
4934   /**
4935    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4936    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4937    */
4938   function completeOutstandingRequest(fn) {
4939     try {
4940       fn.apply(null, sliceArgs(arguments, 1));
4941     } finally {
4942       outstandingRequestCount--;
4943       if (outstandingRequestCount === 0) {
4944         while (outstandingRequestCallbacks.length) {
4945           try {
4946             outstandingRequestCallbacks.pop()();
4947           } catch (e) {
4948             $log.error(e);
4949           }
4950         }
4951       }
4952     }
4953   }
4954
4955   function getHash(url) {
4956     var index = url.indexOf('#');
4957     return index === -1 ? '' : url.substr(index);
4958   }
4959
4960   /**
4961    * @private
4962    * Note: this method is used only by scenario runner
4963    * TODO(vojta): prefix this method with $$ ?
4964    * @param {function()} callback Function that will be called when no outstanding request
4965    */
4966   self.notifyWhenNoOutstandingRequests = function(callback) {
4967     // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4968     // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4969     // regular poller would result in flaky tests.
4970     forEach(pollFns, function(pollFn) { pollFn(); });
4971
4972     if (outstandingRequestCount === 0) {
4973       callback();
4974     } else {
4975       outstandingRequestCallbacks.push(callback);
4976     }
4977   };
4978
4979   //////////////////////////////////////////////////////////////
4980   // Poll Watcher API
4981   //////////////////////////////////////////////////////////////
4982   var pollFns = [],
4983       pollTimeout;
4984
4985   /**
4986    * @name $browser#addPollFn
4987    *
4988    * @param {function()} fn Poll function to add
4989    *
4990    * @description
4991    * Adds a function to the list of functions that poller periodically executes,
4992    * and starts polling if not started yet.
4993    *
4994    * @returns {function()} the added function
4995    */
4996   self.addPollFn = function(fn) {
4997     if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4998     pollFns.push(fn);
4999     return fn;
5000   };
5001
5002   /**
5003    * @param {number} interval How often should browser call poll functions (ms)
5004    * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
5005    *
5006    * @description
5007    * Configures the poller to run in the specified intervals, using the specified
5008    * setTimeout fn and kicks it off.
5009    */
5010   function startPoller(interval, setTimeout) {
5011     (function check() {
5012       forEach(pollFns, function(pollFn) { pollFn(); });
5013       pollTimeout = setTimeout(check, interval);
5014     })();
5015   }
5016
5017   //////////////////////////////////////////////////////////////
5018   // URL API
5019   //////////////////////////////////////////////////////////////
5020
5021   var cachedState, lastHistoryState,
5022       lastBrowserUrl = location.href,
5023       baseElement = document.find('base'),
5024       reloadLocation = null;
5025
5026   cacheState();
5027   lastHistoryState = cachedState;
5028
5029   /**
5030    * @name $browser#url
5031    *
5032    * @description
5033    * GETTER:
5034    * Without any argument, this method just returns current value of location.href.
5035    *
5036    * SETTER:
5037    * With at least one argument, this method sets url to new value.
5038    * If html5 history api supported, pushState/replaceState is used, otherwise
5039    * location.href/location.replace is used.
5040    * Returns its own instance to allow chaining
5041    *
5042    * NOTE: this api is intended for use only by the $location service. Please use the
5043    * {@link ng.$location $location service} to change url.
5044    *
5045    * @param {string} url New url (when used as setter)
5046    * @param {boolean=} replace Should new url replace current history record?
5047    * @param {object=} state object to use with pushState/replaceState
5048    */
5049   self.url = function(url, replace, state) {
5050     // In modern browsers `history.state` is `null` by default; treating it separately
5051     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5052     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5053     if (isUndefined(state)) {
5054       state = null;
5055     }
5056
5057     // Android Browser BFCache causes location, history reference to become stale.
5058     if (location !== window.location) location = window.location;
5059     if (history !== window.history) history = window.history;
5060
5061     // setter
5062     if (url) {
5063       var sameState = lastHistoryState === state;
5064
5065       // Don't change anything if previous and current URLs and states match. This also prevents
5066       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5067       // See https://github.com/angular/angular.js/commit/ffb2701
5068       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5069         return self;
5070       }
5071       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5072       lastBrowserUrl = url;
5073       lastHistoryState = state;
5074       // Don't use history API if only the hash changed
5075       // due to a bug in IE10/IE11 which leads
5076       // to not firing a `hashchange` nor `popstate` event
5077       // in some cases (see #9143).
5078       if ($sniffer.history && (!sameBase || !sameState)) {
5079         history[replace ? 'replaceState' : 'pushState'](state, '', url);
5080         cacheState();
5081         // Do the assignment again so that those two variables are referentially identical.
5082         lastHistoryState = cachedState;
5083       } else {
5084         if (!sameBase || reloadLocation) {
5085           reloadLocation = url;
5086         }
5087         if (replace) {
5088           location.replace(url);
5089         } else if (!sameBase) {
5090           location.href = url;
5091         } else {
5092           location.hash = getHash(url);
5093         }
5094       }
5095       return self;
5096     // getter
5097     } else {
5098       // - reloadLocation is needed as browsers don't allow to read out
5099       //   the new location.href if a reload happened.
5100       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5101       return reloadLocation || location.href.replace(/%27/g,"'");
5102     }
5103   };
5104
5105   /**
5106    * @name $browser#state
5107    *
5108    * @description
5109    * This method is a getter.
5110    *
5111    * Return history.state or null if history.state is undefined.
5112    *
5113    * @returns {object} state
5114    */
5115   self.state = function() {
5116     return cachedState;
5117   };
5118
5119   var urlChangeListeners = [],
5120       urlChangeInit = false;
5121
5122   function cacheStateAndFireUrlChange() {
5123     cacheState();
5124     fireUrlChange();
5125   }
5126
5127   function getCurrentState() {
5128     try {
5129       return history.state;
5130     } catch (e) {
5131       // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5132     }
5133   }
5134
5135   // This variable should be used *only* inside the cacheState function.
5136   var lastCachedState = null;
5137   function cacheState() {
5138     // This should be the only place in $browser where `history.state` is read.
5139     cachedState = getCurrentState();
5140     cachedState = isUndefined(cachedState) ? null : cachedState;
5141
5142     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5143     if (equals(cachedState, lastCachedState)) {
5144       cachedState = lastCachedState;
5145     }
5146     lastCachedState = cachedState;
5147   }
5148
5149   function fireUrlChange() {
5150     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5151       return;
5152     }
5153
5154     lastBrowserUrl = self.url();
5155     lastHistoryState = cachedState;
5156     forEach(urlChangeListeners, function(listener) {
5157       listener(self.url(), cachedState);
5158     });
5159   }
5160
5161   /**
5162    * @name $browser#onUrlChange
5163    *
5164    * @description
5165    * Register callback function that will be called, when url changes.
5166    *
5167    * It's only called when the url is changed from outside of angular:
5168    * - user types different url into address bar
5169    * - user clicks on history (forward/back) button
5170    * - user clicks on a link
5171    *
5172    * It's not called when url is changed by $browser.url() method
5173    *
5174    * The listener gets called with new url as parameter.
5175    *
5176    * NOTE: this api is intended for use only by the $location service. Please use the
5177    * {@link ng.$location $location service} to monitor url changes in angular apps.
5178    *
5179    * @param {function(string)} listener Listener function to be called when url changes.
5180    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5181    */
5182   self.onUrlChange = function(callback) {
5183     // TODO(vojta): refactor to use node's syntax for events
5184     if (!urlChangeInit) {
5185       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5186       // don't fire popstate when user change the address bar and don't fire hashchange when url
5187       // changed by push/replaceState
5188
5189       // html5 history api - popstate event
5190       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5191       // hashchange event
5192       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5193
5194       urlChangeInit = true;
5195     }
5196
5197     urlChangeListeners.push(callback);
5198     return callback;
5199   };
5200
5201   /**
5202    * Checks whether the url has changed outside of Angular.
5203    * Needs to be exported to be able to check for changes that have been done in sync,
5204    * as hashchange/popstate events fire in async.
5205    */
5206   self.$$checkUrlChange = fireUrlChange;
5207
5208   //////////////////////////////////////////////////////////////
5209   // Misc API
5210   //////////////////////////////////////////////////////////////
5211
5212   /**
5213    * @name $browser#baseHref
5214    *
5215    * @description
5216    * Returns current <base href>
5217    * (always relative - without domain)
5218    *
5219    * @returns {string} The current base href
5220    */
5221   self.baseHref = function() {
5222     var href = baseElement.attr('href');
5223     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5224   };
5225
5226   //////////////////////////////////////////////////////////////
5227   // Cookies API
5228   //////////////////////////////////////////////////////////////
5229   var lastCookies = {};
5230   var lastCookieString = '';
5231   var cookiePath = self.baseHref();
5232
5233   function safeDecodeURIComponent(str) {
5234     try {
5235       return decodeURIComponent(str);
5236     } catch (e) {
5237       return str;
5238     }
5239   }
5240
5241   /**
5242    * @name $browser#cookies
5243    *
5244    * @param {string=} name Cookie name
5245    * @param {string=} value Cookie value
5246    *
5247    * @description
5248    * The cookies method provides a 'private' low level access to browser cookies.
5249    * It is not meant to be used directly, use the $cookie service instead.
5250    *
5251    * The return values vary depending on the arguments that the method was called with as follows:
5252    *
5253    * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
5254    *   it
5255    * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
5256    * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
5257    *   way)
5258    *
5259    * @returns {Object} Hash of all cookies (if called without any parameter)
5260    */
5261   self.cookies = function(name, value) {
5262     var cookieLength, cookieArray, cookie, i, index;
5263
5264     if (name) {
5265       if (value === undefined) {
5266         rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
5267                                 ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
5268       } else {
5269         if (isString(value)) {
5270           cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
5271                                 ';path=' + cookiePath).length + 1;
5272
5273           // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
5274           // - 300 cookies
5275           // - 20 cookies per unique domain
5276           // - 4096 bytes per cookie
5277           if (cookieLength > 4096) {
5278             $log.warn("Cookie '" + name +
5279               "' possibly not set or overflowed because it was too large (" +
5280               cookieLength + " > 4096 bytes)!");
5281           }
5282         }
5283       }
5284     } else {
5285       if (rawDocument.cookie !== lastCookieString) {
5286         lastCookieString = rawDocument.cookie;
5287         cookieArray = lastCookieString.split("; ");
5288         lastCookies = {};
5289
5290         for (i = 0; i < cookieArray.length; i++) {
5291           cookie = cookieArray[i];
5292           index = cookie.indexOf('=');
5293           if (index > 0) { //ignore nameless cookies
5294             name = safeDecodeURIComponent(cookie.substring(0, index));
5295             // the first value that is seen for a cookie is the most
5296             // specific one.  values for the same cookie name that
5297             // follow are for less specific paths.
5298             if (lastCookies[name] === undefined) {
5299               lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
5300             }
5301           }
5302         }
5303       }
5304       return lastCookies;
5305     }
5306   };
5307
5308
5309   /**
5310    * @name $browser#defer
5311    * @param {function()} fn A function, who's execution should be deferred.
5312    * @param {number=} [delay=0] of milliseconds to defer the function execution.
5313    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5314    *
5315    * @description
5316    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5317    *
5318    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5319    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5320    * via `$browser.defer.flush()`.
5321    *
5322    */
5323   self.defer = function(fn, delay) {
5324     var timeoutId;
5325     outstandingRequestCount++;
5326     timeoutId = setTimeout(function() {
5327       delete pendingDeferIds[timeoutId];
5328       completeOutstandingRequest(fn);
5329     }, delay || 0);
5330     pendingDeferIds[timeoutId] = true;
5331     return timeoutId;
5332   };
5333
5334
5335   /**
5336    * @name $browser#defer.cancel
5337    *
5338    * @description
5339    * Cancels a deferred task identified with `deferId`.
5340    *
5341    * @param {*} deferId Token returned by the `$browser.defer` function.
5342    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5343    *                    canceled.
5344    */
5345   self.defer.cancel = function(deferId) {
5346     if (pendingDeferIds[deferId]) {
5347       delete pendingDeferIds[deferId];
5348       clearTimeout(deferId);
5349       completeOutstandingRequest(noop);
5350       return true;
5351     }
5352     return false;
5353   };
5354
5355 }
5356
5357 function $BrowserProvider() {
5358   this.$get = ['$window', '$log', '$sniffer', '$document',
5359       function($window, $log, $sniffer, $document) {
5360         return new Browser($window, $document, $log, $sniffer);
5361       }];
5362 }
5363
5364 /**
5365  * @ngdoc service
5366  * @name $cacheFactory
5367  *
5368  * @description
5369  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5370  * them.
5371  *
5372  * ```js
5373  *
5374  *  var cache = $cacheFactory('cacheId');
5375  *  expect($cacheFactory.get('cacheId')).toBe(cache);
5376  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5377  *
5378  *  cache.put("key", "value");
5379  *  cache.put("another key", "another value");
5380  *
5381  *  // We've specified no options on creation
5382  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5383  *
5384  * ```
5385  *
5386  *
5387  * @param {string} cacheId Name or id of the newly created cache.
5388  * @param {object=} options Options object that specifies the cache behavior. Properties:
5389  *
5390  *   - `{number=}` `capacity` — turns the cache into LRU cache.
5391  *
5392  * @returns {object} Newly created cache object with the following set of methods:
5393  *
5394  * - `{object}` `info()` — Returns id, size, and options of cache.
5395  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5396  *   it.
5397  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5398  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5399  * - `{void}` `removeAll()` — Removes all cached values.
5400  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5401  *
5402  * @example
5403    <example module="cacheExampleApp">
5404      <file name="index.html">
5405        <div ng-controller="CacheController">
5406          <input ng-model="newCacheKey" placeholder="Key">
5407          <input ng-model="newCacheValue" placeholder="Value">
5408          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5409
5410          <p ng-if="keys.length">Cached Values</p>
5411          <div ng-repeat="key in keys">
5412            <span ng-bind="key"></span>
5413            <span>: </span>
5414            <b ng-bind="cache.get(key)"></b>
5415          </div>
5416
5417          <p>Cache Info</p>
5418          <div ng-repeat="(key, value) in cache.info()">
5419            <span ng-bind="key"></span>
5420            <span>: </span>
5421            <b ng-bind="value"></b>
5422          </div>
5423        </div>
5424      </file>
5425      <file name="script.js">
5426        angular.module('cacheExampleApp', []).
5427          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
5428            $scope.keys = [];
5429            $scope.cache = $cacheFactory('cacheId');
5430            $scope.put = function(key, value) {
5431              if ($scope.cache.get(key) === undefined) {
5432                $scope.keys.push(key);
5433              }
5434              $scope.cache.put(key, value === undefined ? null : value);
5435            };
5436          }]);
5437      </file>
5438      <file name="style.css">
5439        p {
5440          margin: 10px 0 3px;
5441        }
5442      </file>
5443    </example>
5444  */
5445 function $CacheFactoryProvider() {
5446
5447   this.$get = function() {
5448     var caches = {};
5449
5450     function cacheFactory(cacheId, options) {
5451       if (cacheId in caches) {
5452         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
5453       }
5454
5455       var size = 0,
5456           stats = extend({}, options, {id: cacheId}),
5457           data = {},
5458           capacity = (options && options.capacity) || Number.MAX_VALUE,
5459           lruHash = {},
5460           freshEnd = null,
5461           staleEnd = null;
5462
5463       /**
5464        * @ngdoc type
5465        * @name $cacheFactory.Cache
5466        *
5467        * @description
5468        * A cache object used to store and retrieve data, primarily used by
5469        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
5470        * templates and other data.
5471        *
5472        * ```js
5473        *  angular.module('superCache')
5474        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
5475        *      return $cacheFactory('super-cache');
5476        *    }]);
5477        * ```
5478        *
5479        * Example test:
5480        *
5481        * ```js
5482        *  it('should behave like a cache', inject(function(superCache) {
5483        *    superCache.put('key', 'value');
5484        *    superCache.put('another key', 'another value');
5485        *
5486        *    expect(superCache.info()).toEqual({
5487        *      id: 'super-cache',
5488        *      size: 2
5489        *    });
5490        *
5491        *    superCache.remove('another key');
5492        *    expect(superCache.get('another key')).toBeUndefined();
5493        *
5494        *    superCache.removeAll();
5495        *    expect(superCache.info()).toEqual({
5496        *      id: 'super-cache',
5497        *      size: 0
5498        *    });
5499        *  }));
5500        * ```
5501        */
5502       return caches[cacheId] = {
5503
5504         /**
5505          * @ngdoc method
5506          * @name $cacheFactory.Cache#put
5507          * @kind function
5508          *
5509          * @description
5510          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
5511          * retrieved later, and incrementing the size of the cache if the key was not already
5512          * present in the cache. If behaving like an LRU cache, it will also remove stale
5513          * entries from the set.
5514          *
5515          * It will not insert undefined values into the cache.
5516          *
5517          * @param {string} key the key under which the cached data is stored.
5518          * @param {*} value the value to store alongside the key. If it is undefined, the key
5519          *    will not be stored.
5520          * @returns {*} the value stored.
5521          */
5522         put: function(key, value) {
5523           if (capacity < Number.MAX_VALUE) {
5524             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
5525
5526             refresh(lruEntry);
5527           }
5528
5529           if (isUndefined(value)) return;
5530           if (!(key in data)) size++;
5531           data[key] = value;
5532
5533           if (size > capacity) {
5534             this.remove(staleEnd.key);
5535           }
5536
5537           return value;
5538         },
5539
5540         /**
5541          * @ngdoc method
5542          * @name $cacheFactory.Cache#get
5543          * @kind function
5544          *
5545          * @description
5546          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
5547          *
5548          * @param {string} key the key of the data to be retrieved
5549          * @returns {*} the value stored.
5550          */
5551         get: function(key) {
5552           if (capacity < Number.MAX_VALUE) {
5553             var lruEntry = lruHash[key];
5554
5555             if (!lruEntry) return;
5556
5557             refresh(lruEntry);
5558           }
5559
5560           return data[key];
5561         },
5562
5563
5564         /**
5565          * @ngdoc method
5566          * @name $cacheFactory.Cache#remove
5567          * @kind function
5568          *
5569          * @description
5570          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
5571          *
5572          * @param {string} key the key of the entry to be removed
5573          */
5574         remove: function(key) {
5575           if (capacity < Number.MAX_VALUE) {
5576             var lruEntry = lruHash[key];
5577
5578             if (!lruEntry) return;
5579
5580             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
5581             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
5582             link(lruEntry.n,lruEntry.p);
5583
5584             delete lruHash[key];
5585           }
5586
5587           delete data[key];
5588           size--;
5589         },
5590
5591
5592         /**
5593          * @ngdoc method
5594          * @name $cacheFactory.Cache#removeAll
5595          * @kind function
5596          *
5597          * @description
5598          * Clears the cache object of any entries.
5599          */
5600         removeAll: function() {
5601           data = {};
5602           size = 0;
5603           lruHash = {};
5604           freshEnd = staleEnd = null;
5605         },
5606
5607
5608         /**
5609          * @ngdoc method
5610          * @name $cacheFactory.Cache#destroy
5611          * @kind function
5612          *
5613          * @description
5614          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
5615          * removing it from the {@link $cacheFactory $cacheFactory} set.
5616          */
5617         destroy: function() {
5618           data = null;
5619           stats = null;
5620           lruHash = null;
5621           delete caches[cacheId];
5622         },
5623
5624
5625         /**
5626          * @ngdoc method
5627          * @name $cacheFactory.Cache#info
5628          * @kind function
5629          *
5630          * @description
5631          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5632          *
5633          * @returns {object} an object with the following properties:
5634          *   <ul>
5635          *     <li>**id**: the id of the cache instance</li>
5636          *     <li>**size**: the number of entries kept in the cache instance</li>
5637          *     <li>**...**: any additional properties from the options object when creating the
5638          *       cache.</li>
5639          *   </ul>
5640          */
5641         info: function() {
5642           return extend({}, stats, {size: size});
5643         }
5644       };
5645
5646
5647       /**
5648        * makes the `entry` the freshEnd of the LRU linked list
5649        */
5650       function refresh(entry) {
5651         if (entry != freshEnd) {
5652           if (!staleEnd) {
5653             staleEnd = entry;
5654           } else if (staleEnd == entry) {
5655             staleEnd = entry.n;
5656           }
5657
5658           link(entry.n, entry.p);
5659           link(entry, freshEnd);
5660           freshEnd = entry;
5661           freshEnd.n = null;
5662         }
5663       }
5664
5665
5666       /**
5667        * bidirectionally links two entries of the LRU linked list
5668        */
5669       function link(nextEntry, prevEntry) {
5670         if (nextEntry != prevEntry) {
5671           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5672           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5673         }
5674       }
5675     }
5676
5677
5678   /**
5679    * @ngdoc method
5680    * @name $cacheFactory#info
5681    *
5682    * @description
5683    * Get information about all the caches that have been created
5684    *
5685    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5686    */
5687     cacheFactory.info = function() {
5688       var info = {};
5689       forEach(caches, function(cache, cacheId) {
5690         info[cacheId] = cache.info();
5691       });
5692       return info;
5693     };
5694
5695
5696   /**
5697    * @ngdoc method
5698    * @name $cacheFactory#get
5699    *
5700    * @description
5701    * Get access to a cache object by the `cacheId` used when it was created.
5702    *
5703    * @param {string} cacheId Name or id of a cache to access.
5704    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5705    */
5706     cacheFactory.get = function(cacheId) {
5707       return caches[cacheId];
5708     };
5709
5710
5711     return cacheFactory;
5712   };
5713 }
5714
5715 /**
5716  * @ngdoc service
5717  * @name $templateCache
5718  *
5719  * @description
5720  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5721  * can load templates directly into the cache in a `script` tag, or by consuming the
5722  * `$templateCache` service directly.
5723  *
5724  * Adding via the `script` tag:
5725  *
5726  * ```html
5727  *   <script type="text/ng-template" id="templateId.html">
5728  *     <p>This is the content of the template</p>
5729  *   </script>
5730  * ```
5731  *
5732  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5733  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
5734  * element with ng-app attribute), otherwise the template will be ignored.
5735  *
5736  * Adding via the `$templateCache` service:
5737  *
5738  * ```js
5739  * var myApp = angular.module('myApp', []);
5740  * myApp.run(function($templateCache) {
5741  *   $templateCache.put('templateId.html', 'This is the content of the template');
5742  * });
5743  * ```
5744  *
5745  * To retrieve the template later, simply use it in your HTML:
5746  * ```html
5747  * <div ng-include=" 'templateId.html' "></div>
5748  * ```
5749  *
5750  * or get it via Javascript:
5751  * ```js
5752  * $templateCache.get('templateId.html')
5753  * ```
5754  *
5755  * See {@link ng.$cacheFactory $cacheFactory}.
5756  *
5757  */
5758 function $TemplateCacheProvider() {
5759   this.$get = ['$cacheFactory', function($cacheFactory) {
5760     return $cacheFactory('templates');
5761   }];
5762 }
5763
5764 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5765  *     Any commits to this file should be reviewed with security in mind.  *
5766  *   Changes to this file can potentially create security vulnerabilities. *
5767  *          An approval from 2 Core members with history of modifying      *
5768  *                         this file is required.                          *
5769  *                                                                         *
5770  *  Does the change somehow allow for arbitrary javascript to be executed? *
5771  *    Or allows for someone to change the prototype of built-in objects?   *
5772  *     Or gives undesired access to variables likes document or window?    *
5773  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5774
5775 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5776  *
5777  * DOM-related variables:
5778  *
5779  * - "node" - DOM Node
5780  * - "element" - DOM Element or Node
5781  * - "$node" or "$element" - jqLite-wrapped node or element
5782  *
5783  *
5784  * Compiler related stuff:
5785  *
5786  * - "linkFn" - linking fn of a single directive
5787  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5788  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5789  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5790  */
5791
5792
5793 /**
5794  * @ngdoc service
5795  * @name $compile
5796  * @kind function
5797  *
5798  * @description
5799  * Compiles an HTML string or DOM into a template and produces a template function, which
5800  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5801  *
5802  * The compilation is a process of walking the DOM tree and matching DOM elements to
5803  * {@link ng.$compileProvider#directive directives}.
5804  *
5805  * <div class="alert alert-warning">
5806  * **Note:** This document is an in-depth reference of all directive options.
5807  * For a gentle introduction to directives with examples of common use cases,
5808  * see the {@link guide/directive directive guide}.
5809  * </div>
5810  *
5811  * ## Comprehensive Directive API
5812  *
5813  * There are many different options for a directive.
5814  *
5815  * The difference resides in the return value of the factory function.
5816  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5817  * or just the `postLink` function (all other properties will have the default values).
5818  *
5819  * <div class="alert alert-success">
5820  * **Best Practice:** It's recommended to use the "directive definition object" form.
5821  * </div>
5822  *
5823  * Here's an example directive declared with a Directive Definition Object:
5824  *
5825  * ```js
5826  *   var myModule = angular.module(...);
5827  *
5828  *   myModule.directive('directiveName', function factory(injectables) {
5829  *     var directiveDefinitionObject = {
5830  *       priority: 0,
5831  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
5832  *       // or
5833  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5834  *       transclude: false,
5835  *       restrict: 'A',
5836  *       templateNamespace: 'html',
5837  *       scope: false,
5838  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5839  *       controllerAs: 'stringIdentifier',
5840  *       bindToController: false,
5841  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5842  *       compile: function compile(tElement, tAttrs, transclude) {
5843  *         return {
5844  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5845  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5846  *         }
5847  *         // or
5848  *         // return function postLink( ... ) { ... }
5849  *       },
5850  *       // or
5851  *       // link: {
5852  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5853  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5854  *       // }
5855  *       // or
5856  *       // link: function postLink( ... ) { ... }
5857  *     };
5858  *     return directiveDefinitionObject;
5859  *   });
5860  * ```
5861  *
5862  * <div class="alert alert-warning">
5863  * **Note:** Any unspecified options will use the default value. You can see the default values below.
5864  * </div>
5865  *
5866  * Therefore the above can be simplified as:
5867  *
5868  * ```js
5869  *   var myModule = angular.module(...);
5870  *
5871  *   myModule.directive('directiveName', function factory(injectables) {
5872  *     var directiveDefinitionObject = {
5873  *       link: function postLink(scope, iElement, iAttrs) { ... }
5874  *     };
5875  *     return directiveDefinitionObject;
5876  *     // or
5877  *     // return function postLink(scope, iElement, iAttrs) { ... }
5878  *   });
5879  * ```
5880  *
5881  *
5882  *
5883  * ### Directive Definition Object
5884  *
5885  * The directive definition object provides instructions to the {@link ng.$compile
5886  * compiler}. The attributes are:
5887  *
5888  * #### `multiElement`
5889  * When this property is set to true, the HTML compiler will collect DOM nodes between
5890  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
5891  * together as the directive elements. It is recommended that this feature be used on directives
5892  * which are not strictly behavioural (such as {@link ngClick}), and which
5893  * do not manipulate or replace child nodes (such as {@link ngInclude}).
5894  *
5895  * #### `priority`
5896  * When there are multiple directives defined on a single DOM element, sometimes it
5897  * is necessary to specify the order in which the directives are applied. The `priority` is used
5898  * to sort the directives before their `compile` functions get called. Priority is defined as a
5899  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5900  * are also run in priority order, but post-link functions are run in reverse order. The order
5901  * of directives with the same priority is undefined. The default priority is `0`.
5902  *
5903  * #### `terminal`
5904  * If set to true then the current `priority` will be the last set of directives
5905  * which will execute (any directives at the current priority will still execute
5906  * as the order of execution on same `priority` is undefined). Note that expressions
5907  * and other directives used in the directive's template will also be excluded from execution.
5908  *
5909  * #### `scope`
5910  * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5911  * same element request a new scope, only one new scope is created. The new scope rule does not
5912  * apply for the root of the template since the root of the template always gets a new scope.
5913  *
5914  * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5915  * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5916  * when creating reusable components, which should not accidentally read or modify data in the
5917  * parent scope.
5918  *
5919  * The 'isolate' scope takes an object hash which defines a set of local scope properties
5920  * derived from the parent scope. These local properties are useful for aliasing values for
5921  * templates. Locals definition is a hash of local scope property to its source:
5922  *
5923  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5924  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5925  *   attribute name is assumed to be the same as the local name.
5926  *   Given `<widget my-attr="hello {{name}}">` and widget definition
5927  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5928  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5929  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5930  *   component scope).
5931  *
5932  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5933  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5934  *   name is specified then the attribute name is assumed to be the same as the local name.
5935  *   Given `<widget my-attr="parentModel">` and widget definition of
5936  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5937  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5938  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5939  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5940  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
5941  *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
5942  *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
5943  *
5944  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5945  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5946  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5947  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5948  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5949  *   pass data from the isolated scope via an expression to the parent scope, this can be
5950  *   done by passing a map of local variable names and values into the expression wrapper fn.
5951  *   For example, if the expression is `increment(amount)` then we can specify the amount value
5952  *   by calling the `localFn` as `localFn({amount: 22})`.
5953  *
5954  *
5955  * #### `bindToController`
5956  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
5957  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
5958  * is instantiated, the initial values of the isolate scope bindings are already available.
5959  *
5960  * #### `controller`
5961  * Controller constructor function. The controller is instantiated before the
5962  * pre-linking phase and it is shared with other directives (see
5963  * `require` attribute). This allows the directives to communicate with each other and augment
5964  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5965  *
5966  * * `$scope` - Current scope associated with the element
5967  * * `$element` - Current element
5968  * * `$attrs` - Current attributes object for the element
5969  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
5970  *   `function([scope], cloneLinkingFn, futureParentElement)`.
5971  *    * `scope`: optional argument to override the scope.
5972  *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
5973  *    * `futureParentElement`:
5974  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
5975  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
5976  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
5977  *          and when the `cloneLinkinFn` is passed,
5978  *          as those elements need to created and cloned in a special way when they are defined outside their
5979  *          usual containers (e.g. like `<svg>`).
5980  *        * See also the `directive.templateNamespace` property.
5981  *
5982  *
5983  * #### `require`
5984  * Require another directive and inject its controller as the fourth argument to the linking function. The
5985  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5986  * injected argument will be an array in corresponding order. If no such directive can be
5987  * found, or if the directive does not have a controller, then an error is raised (unless no link function
5988  * is specified, in which case error checking is skipped). The name can be prefixed with:
5989  *
5990  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5991  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5992  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5993  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5994  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5995  *   `null` to the `link` fn if not found.
5996  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
5997  *   `null` to the `link` fn if not found.
5998  *
5999  *
6000  * #### `controllerAs`
6001  * Controller alias at the directive scope. An alias for the controller so it
6002  * can be referenced at the directive template. The directive needs to define a scope for this
6003  * configuration to be used. Useful in the case when directive is used as component.
6004  *
6005  *
6006  * #### `restrict`
6007  * String of subset of `EACM` which restricts the directive to a specific directive
6008  * declaration style. If omitted, the defaults (elements and attributes) are used.
6009  *
6010  * * `E` - Element name (default): `<my-directive></my-directive>`
6011  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6012  * * `C` - Class: `<div class="my-directive: exp;"></div>`
6013  * * `M` - Comment: `<!-- directive: my-directive exp -->`
6014  *
6015  *
6016  * #### `templateNamespace`
6017  * String representing the document type used by the markup in the template.
6018  * AngularJS needs this information as those elements need to be created and cloned
6019  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6020  *
6021  * * `html` - All root nodes in the template are HTML. Root nodes may also be
6022  *   top-level elements such as `<svg>` or `<math>`.
6023  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6024  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6025  *
6026  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6027  *
6028  * #### `template`
6029  * HTML markup that may:
6030  * * Replace the contents of the directive's element (default).
6031  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6032  * * Wrap the contents of the directive's element (if `transclude` is true).
6033  *
6034  * Value may be:
6035  *
6036  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6037  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6038  *   function api below) and returns a string value.
6039  *
6040  *
6041  * #### `templateUrl`
6042  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6043  *
6044  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6045  * for later when the template has been resolved.  In the meantime it will continue to compile and link
6046  * sibling and parent elements as though this element had not contained any directives.
6047  *
6048  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6049  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6050  * case when only one deeply nested directive has `templateUrl`.
6051  *
6052  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6053  *
6054  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6055  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6056  * a string value representing the url.  In either case, the template URL is passed through {@link
6057  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6058  *
6059  *
6060  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6061  * specify what the template should replace. Defaults to `false`.
6062  *
6063  * * `true` - the template will replace the directive's element.
6064  * * `false` - the template will replace the contents of the directive's element.
6065  *
6066  * The replacement process migrates all of the attributes / classes from the old element to the new
6067  * one. See the {@link guide/directive#template-expanding-directive
6068  * Directives Guide} for an example.
6069  *
6070  * There are very few scenarios where element replacement is required for the application function,
6071  * the main one being reusable custom components that are used within SVG contexts
6072  * (because SVG doesn't work with custom elements in the DOM tree).
6073  *
6074  * #### `transclude`
6075  * Extract the contents of the element where the directive appears and make it available to the directive.
6076  * The contents are compiled and provided to the directive as a **transclusion function**. See the
6077  * {@link $compile#transclusion Transclusion} section below.
6078  *
6079  * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6080  * directive's element or the entire element:
6081  *
6082  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6083  * * `'element'` - transclude the whole of the directive's element including any directives on this
6084  *   element that defined at a lower priority than this directive. When used, the `template`
6085  *   property is ignored.
6086  *
6087  *
6088  * #### `compile`
6089  *
6090  * ```js
6091  *   function compile(tElement, tAttrs, transclude) { ... }
6092  * ```
6093  *
6094  * The compile function deals with transforming the template DOM. Since most directives do not do
6095  * template transformation, it is not used often. The compile function takes the following arguments:
6096  *
6097  *   * `tElement` - template element - The element where the directive has been declared. It is
6098  *     safe to do template transformation on the element and child elements only.
6099  *
6100  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6101  *     between all directive compile functions.
6102  *
6103  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6104  *
6105  * <div class="alert alert-warning">
6106  * **Note:** The template instance and the link instance may be different objects if the template has
6107  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6108  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6109  * should be done in a linking function rather than in a compile function.
6110  * </div>
6111
6112  * <div class="alert alert-warning">
6113  * **Note:** The compile function cannot handle directives that recursively use themselves in their
6114  * own templates or compile functions. Compiling these directives results in an infinite loop and a
6115  * stack overflow errors.
6116  *
6117  * This can be avoided by manually using $compile in the postLink function to imperatively compile
6118  * a directive's template instead of relying on automatic template compilation via `template` or
6119  * `templateUrl` declaration or manual compilation inside the compile function.
6120  * </div>
6121  *
6122  * <div class="alert alert-error">
6123  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6124  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6125  *   to the link function instead.
6126  * </div>
6127
6128  * A compile function can have a return value which can be either a function or an object.
6129  *
6130  * * returning a (post-link) function - is equivalent to registering the linking function via the
6131  *   `link` property of the config object when the compile function is empty.
6132  *
6133  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6134  *   control when a linking function should be called during the linking phase. See info about
6135  *   pre-linking and post-linking functions below.
6136  *
6137  *
6138  * #### `link`
6139  * This property is used only if the `compile` property is not defined.
6140  *
6141  * ```js
6142  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6143  * ```
6144  *
6145  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6146  * executed after the template has been cloned. This is where most of the directive logic will be
6147  * put.
6148  *
6149  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6150  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6151  *
6152  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6153  *     manipulate the children of the element only in `postLink` function since the children have
6154  *     already been linked.
6155  *
6156  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6157  *     between all directive linking functions.
6158  *
6159  *   * `controller` - the directive's required controller instance(s) - Instances are shared
6160  *     among all directives, which allows the directives to use the controllers as a communication
6161  *     channel. The exact value depends on the directive's `require` property:
6162  *       * `string`: the controller instance
6163  *       * `array`: array of controller instances
6164  *       * no controller(s) required: `undefined`
6165  *
6166  *     If a required controller cannot be found, and it is optional, the instance is `null`,
6167  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6168  *
6169  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6170  *     This is the same as the `$transclude`
6171  *     parameter of directive controllers, see there for details.
6172  *     `function([scope], cloneLinkingFn, futureParentElement)`.
6173  *
6174  * #### Pre-linking function
6175  *
6176  * Executed before the child elements are linked. Not safe to do DOM transformation since the
6177  * compiler linking function will fail to locate the correct elements for linking.
6178  *
6179  * #### Post-linking function
6180  *
6181  * Executed after the child elements are linked.
6182  *
6183  * Note that child elements that contain `templateUrl` directives will not have been compiled
6184  * and linked since they are waiting for their template to load asynchronously and their own
6185  * compilation and linking has been suspended until that occurs.
6186  *
6187  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6188  * for their async templates to be resolved.
6189  *
6190  *
6191  * ### Transclusion
6192  *
6193  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
6194  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6195  * scope from where they were taken.
6196  *
6197  * Transclusion is used (often with {@link ngTransclude}) to insert the
6198  * original contents of a directive's element into a specified place in the template of the directive.
6199  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6200  * content has access to the properties on the scope from which it was taken, even if the directive
6201  * has isolated scope.
6202  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6203  *
6204  * This makes it possible for the widget to have private state for its template, while the transcluded
6205  * content has access to its originating scope.
6206  *
6207  * <div class="alert alert-warning">
6208  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6209  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6210  * Testing Transclusion Directives}.
6211  * </div>
6212  *
6213  * #### Transclusion Functions
6214  *
6215  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6216  * function** to the directive's `link` function and `controller`. This transclusion function is a special
6217  * **linking function** that will return the compiled contents linked to a new transclusion scope.
6218  *
6219  * <div class="alert alert-info">
6220  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6221  * ngTransclude will deal with it for us.
6222  * </div>
6223  *
6224  * If you want to manually control the insertion and removal of the transcluded content in your directive
6225  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6226  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6227  *
6228  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6229  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6230  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6231  *
6232  * <div class="alert alert-info">
6233  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6234  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6235  * </div>
6236  *
6237  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6238  * attach function**:
6239  *
6240  * ```js
6241  * var transcludedContent, transclusionScope;
6242  *
6243  * $transclude(function(clone, scope) {
6244  *   element.append(clone);
6245  *   transcludedContent = clone;
6246  *   transclusionScope = scope;
6247  * });
6248  * ```
6249  *
6250  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6251  * associated transclusion scope:
6252  *
6253  * ```js
6254  * transcludedContent.remove();
6255  * transclusionScope.$destroy();
6256  * ```
6257  *
6258  * <div class="alert alert-info">
6259  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6260  * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
6261  * then you are also responsible for calling `$destroy` on the transclusion scope.
6262  * </div>
6263  *
6264  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6265  * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6266  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6267  *
6268  *
6269  * #### Transclusion Scopes
6270  *
6271  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6272  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6273  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6274  * was taken.
6275  *
6276  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6277  * like this:
6278  *
6279  * ```html
6280  * <div ng-app>
6281  *   <div isolate>
6282  *     <div transclusion>
6283  *     </div>
6284  *   </div>
6285  * </div>
6286  * ```
6287  *
6288  * The `$parent` scope hierarchy will look like this:
6289  *
6290  * ```
6291  * - $rootScope
6292  *   - isolate
6293  *     - transclusion
6294  * ```
6295  *
6296  * but the scopes will inherit prototypically from different scopes to their `$parent`.
6297  *
6298  * ```
6299  * - $rootScope
6300  *   - transclusion
6301  * - isolate
6302  * ```
6303  *
6304  *
6305  * ### Attributes
6306  *
6307  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6308  * `link()` or `compile()` functions. It has a variety of uses.
6309  *
6310  * accessing *Normalized attribute names:*
6311  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6312  * the attributes object allows for normalized access to
6313  *   the attributes.
6314  *
6315  * * *Directive inter-communication:* All directives share the same instance of the attributes
6316  *   object which allows the directives to use the attributes object as inter directive
6317  *   communication.
6318  *
6319  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6320  *   allowing other directives to read the interpolated value.
6321  *
6322  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6323  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6324  *   the only way to easily get the actual value because during the linking phase the interpolation
6325  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6326  *
6327  * ```js
6328  * function linkingFn(scope, elm, attrs, ctrl) {
6329  *   // get the attribute value
6330  *   console.log(attrs.ngModel);
6331  *
6332  *   // change the attribute
6333  *   attrs.$set('ngModel', 'new value');
6334  *
6335  *   // observe changes to interpolated attribute
6336  *   attrs.$observe('ngModel', function(value) {
6337  *     console.log('ngModel has changed value to ' + value);
6338  *   });
6339  * }
6340  * ```
6341  *
6342  * ## Example
6343  *
6344  * <div class="alert alert-warning">
6345  * **Note**: Typically directives are registered with `module.directive`. The example below is
6346  * to illustrate how `$compile` works.
6347  * </div>
6348  *
6349  <example module="compileExample">
6350    <file name="index.html">
6351     <script>
6352       angular.module('compileExample', [], function($compileProvider) {
6353         // configure new 'compile' directive by passing a directive
6354         // factory function. The factory function injects the '$compile'
6355         $compileProvider.directive('compile', function($compile) {
6356           // directive factory creates a link function
6357           return function(scope, element, attrs) {
6358             scope.$watch(
6359               function(scope) {
6360                  // watch the 'compile' expression for changes
6361                 return scope.$eval(attrs.compile);
6362               },
6363               function(value) {
6364                 // when the 'compile' expression changes
6365                 // assign it into the current DOM
6366                 element.html(value);
6367
6368                 // compile the new DOM and link it to the current
6369                 // scope.
6370                 // NOTE: we only compile .childNodes so that
6371                 // we don't get into infinite loop compiling ourselves
6372                 $compile(element.contents())(scope);
6373               }
6374             );
6375           };
6376         });
6377       })
6378       .controller('GreeterController', ['$scope', function($scope) {
6379         $scope.name = 'Angular';
6380         $scope.html = 'Hello {{name}}';
6381       }]);
6382     </script>
6383     <div ng-controller="GreeterController">
6384       <input ng-model="name"> <br>
6385       <textarea ng-model="html"></textarea> <br>
6386       <div compile="html"></div>
6387     </div>
6388    </file>
6389    <file name="protractor.js" type="protractor">
6390      it('should auto compile', function() {
6391        var textarea = $('textarea');
6392        var output = $('div[compile]');
6393        // The initial state reads 'Hello Angular'.
6394        expect(output.getText()).toBe('Hello Angular');
6395        textarea.clear();
6396        textarea.sendKeys('{{name}}!');
6397        expect(output.getText()).toBe('Angular!');
6398      });
6399    </file>
6400  </example>
6401
6402  *
6403  *
6404  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
6405  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
6406  *
6407  * <div class="alert alert-error">
6408  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
6409  *   e.g. will not use the right outer scope. Please pass the transclude function as a
6410  *   `parentBoundTranscludeFn` to the link function instead.
6411  * </div>
6412  *
6413  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
6414  *                 root element(s), not their children)
6415  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
6416  * (a DOM element/tree) to a scope. Where:
6417  *
6418  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
6419  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
6420  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
6421  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
6422  *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
6423  *
6424  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
6425  *      * `scope` - is the current scope with which the linking function is working with.
6426  *
6427  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
6428  *  keys may be used to control linking behavior:
6429  *
6430  *      * `parentBoundTranscludeFn` - the transclude function made available to
6431  *        directives; if given, it will be passed through to the link functions of
6432  *        directives found in `element` during compilation.
6433  *      * `transcludeControllers` - an object hash with keys that map controller names
6434  *        to controller instances; if given, it will make the controllers
6435  *        available to directives.
6436  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6437  *        the cloned elements; only needed for transcludes that are allowed to contain non html
6438  *        elements (e.g. SVG elements). See also the directive.controller property.
6439  *
6440  * Calling the linking function returns the element of the template. It is either the original
6441  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
6442  *
6443  * After linking the view is not updated until after a call to $digest which typically is done by
6444  * Angular automatically.
6445  *
6446  * If you need access to the bound view, there are two ways to do it:
6447  *
6448  * - If you are not asking the linking function to clone the template, create the DOM element(s)
6449  *   before you send them to the compiler and keep this reference around.
6450  *   ```js
6451  *     var element = $compile('<p>{{total}}</p>')(scope);
6452  *   ```
6453  *
6454  * - if on the other hand, you need the element to be cloned, the view reference from the original
6455  *   example would not point to the clone, but rather to the original template that was cloned. In
6456  *   this case, you can access the clone via the cloneAttachFn:
6457  *   ```js
6458  *     var templateElement = angular.element('<p>{{total}}</p>'),
6459  *         scope = ....;
6460  *
6461  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
6462  *       //attach the clone to DOM document at the right place
6463  *     });
6464  *
6465  *     //now we have reference to the cloned DOM via `clonedElement`
6466  *   ```
6467  *
6468  *
6469  * For information on how the compiler works, see the
6470  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
6471  */
6472
6473 var $compileMinErr = minErr('$compile');
6474
6475 /**
6476  * @ngdoc provider
6477  * @name $compileProvider
6478  *
6479  * @description
6480  */
6481 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
6482 function $CompileProvider($provide, $$sanitizeUriProvider) {
6483   var hasDirectives = {},
6484       Suffix = 'Directive',
6485       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
6486       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
6487       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
6488       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
6489
6490   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
6491   // The assumption is that future DOM event attribute names will begin with
6492   // 'on' and be composed of only English letters.
6493   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
6494
6495   function parseIsolateBindings(scope, directiveName) {
6496     var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
6497
6498     var bindings = {};
6499
6500     forEach(scope, function(definition, scopeName) {
6501       var match = definition.match(LOCAL_REGEXP);
6502
6503       if (!match) {
6504         throw $compileMinErr('iscp',
6505             "Invalid isolate scope definition for directive '{0}'." +
6506             " Definition: {... {1}: '{2}' ...}",
6507             directiveName, scopeName, definition);
6508       }
6509
6510       bindings[scopeName] = {
6511         mode: match[1][0],
6512         collection: match[2] === '*',
6513         optional: match[3] === '?',
6514         attrName: match[4] || scopeName
6515       };
6516     });
6517
6518     return bindings;
6519   }
6520
6521   /**
6522    * @ngdoc method
6523    * @name $compileProvider#directive
6524    * @kind function
6525    *
6526    * @description
6527    * Register a new directive with the compiler.
6528    *
6529    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
6530    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
6531    *    names and the values are the factories.
6532    * @param {Function|Array} directiveFactory An injectable directive factory function. See
6533    *    {@link guide/directive} for more info.
6534    * @returns {ng.$compileProvider} Self for chaining.
6535    */
6536    this.directive = function registerDirective(name, directiveFactory) {
6537     assertNotHasOwnProperty(name, 'directive');
6538     if (isString(name)) {
6539       assertArg(directiveFactory, 'directiveFactory');
6540       if (!hasDirectives.hasOwnProperty(name)) {
6541         hasDirectives[name] = [];
6542         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
6543           function($injector, $exceptionHandler) {
6544             var directives = [];
6545             forEach(hasDirectives[name], function(directiveFactory, index) {
6546               try {
6547                 var directive = $injector.invoke(directiveFactory);
6548                 if (isFunction(directive)) {
6549                   directive = { compile: valueFn(directive) };
6550                 } else if (!directive.compile && directive.link) {
6551                   directive.compile = valueFn(directive.link);
6552                 }
6553                 directive.priority = directive.priority || 0;
6554                 directive.index = index;
6555                 directive.name = directive.name || name;
6556                 directive.require = directive.require || (directive.controller && directive.name);
6557                 directive.restrict = directive.restrict || 'EA';
6558                 if (isObject(directive.scope)) {
6559                   directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name);
6560                 }
6561                 directives.push(directive);
6562               } catch (e) {
6563                 $exceptionHandler(e);
6564               }
6565             });
6566             return directives;
6567           }]);
6568       }
6569       hasDirectives[name].push(directiveFactory);
6570     } else {
6571       forEach(name, reverseParams(registerDirective));
6572     }
6573     return this;
6574   };
6575
6576
6577   /**
6578    * @ngdoc method
6579    * @name $compileProvider#aHrefSanitizationWhitelist
6580    * @kind function
6581    *
6582    * @description
6583    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6584    * urls during a[href] sanitization.
6585    *
6586    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
6587    *
6588    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
6589    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
6590    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6591    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6592    *
6593    * @param {RegExp=} regexp New regexp to whitelist urls with.
6594    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6595    *    chaining otherwise.
6596    */
6597   this.aHrefSanitizationWhitelist = function(regexp) {
6598     if (isDefined(regexp)) {
6599       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
6600       return this;
6601     } else {
6602       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
6603     }
6604   };
6605
6606
6607   /**
6608    * @ngdoc method
6609    * @name $compileProvider#imgSrcSanitizationWhitelist
6610    * @kind function
6611    *
6612    * @description
6613    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6614    * urls during img[src] sanitization.
6615    *
6616    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
6617    *
6618    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
6619    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
6620    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6621    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6622    *
6623    * @param {RegExp=} regexp New regexp to whitelist urls with.
6624    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6625    *    chaining otherwise.
6626    */
6627   this.imgSrcSanitizationWhitelist = function(regexp) {
6628     if (isDefined(regexp)) {
6629       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
6630       return this;
6631     } else {
6632       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
6633     }
6634   };
6635
6636   /**
6637    * @ngdoc method
6638    * @name  $compileProvider#debugInfoEnabled
6639    *
6640    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
6641    * current debugInfoEnabled state
6642    * @returns {*} current value if used as getter or itself (chaining) if used as setter
6643    *
6644    * @kind function
6645    *
6646    * @description
6647    * Call this method to enable/disable various debug runtime information in the compiler such as adding
6648    * binding information and a reference to the current scope on to DOM elements.
6649    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
6650    * * `ng-binding` CSS class
6651    * * `$binding` data property containing an array of the binding expressions
6652    *
6653    * You may want to disable this in production for a significant performance boost. See
6654    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
6655    *
6656    * The default value is true.
6657    */
6658   var debugInfoEnabled = true;
6659   this.debugInfoEnabled = function(enabled) {
6660     if (isDefined(enabled)) {
6661       debugInfoEnabled = enabled;
6662       return this;
6663     }
6664     return debugInfoEnabled;
6665   };
6666
6667   this.$get = [
6668             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
6669             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
6670     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
6671              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
6672
6673     var Attributes = function(element, attributesToCopy) {
6674       if (attributesToCopy) {
6675         var keys = Object.keys(attributesToCopy);
6676         var i, l, key;
6677
6678         for (i = 0, l = keys.length; i < l; i++) {
6679           key = keys[i];
6680           this[key] = attributesToCopy[key];
6681         }
6682       } else {
6683         this.$attr = {};
6684       }
6685
6686       this.$$element = element;
6687     };
6688
6689     Attributes.prototype = {
6690       /**
6691        * @ngdoc method
6692        * @name $compile.directive.Attributes#$normalize
6693        * @kind function
6694        *
6695        * @description
6696        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
6697        * `data-`) to its normalized, camelCase form.
6698        *
6699        * Also there is special case for Moz prefix starting with upper case letter.
6700        *
6701        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
6702        *
6703        * @param {string} name Name to normalize
6704        */
6705       $normalize: directiveNormalize,
6706
6707
6708       /**
6709        * @ngdoc method
6710        * @name $compile.directive.Attributes#$addClass
6711        * @kind function
6712        *
6713        * @description
6714        * Adds the CSS class value specified by the classVal parameter to the element. If animations
6715        * are enabled then an animation will be triggered for the class addition.
6716        *
6717        * @param {string} classVal The className value that will be added to the element
6718        */
6719       $addClass: function(classVal) {
6720         if (classVal && classVal.length > 0) {
6721           $animate.addClass(this.$$element, classVal);
6722         }
6723       },
6724
6725       /**
6726        * @ngdoc method
6727        * @name $compile.directive.Attributes#$removeClass
6728        * @kind function
6729        *
6730        * @description
6731        * Removes the CSS class value specified by the classVal parameter from the element. If
6732        * animations are enabled then an animation will be triggered for the class removal.
6733        *
6734        * @param {string} classVal The className value that will be removed from the element
6735        */
6736       $removeClass: function(classVal) {
6737         if (classVal && classVal.length > 0) {
6738           $animate.removeClass(this.$$element, classVal);
6739         }
6740       },
6741
6742       /**
6743        * @ngdoc method
6744        * @name $compile.directive.Attributes#$updateClass
6745        * @kind function
6746        *
6747        * @description
6748        * Adds and removes the appropriate CSS class values to the element based on the difference
6749        * between the new and old CSS class values (specified as newClasses and oldClasses).
6750        *
6751        * @param {string} newClasses The current CSS className value
6752        * @param {string} oldClasses The former CSS className value
6753        */
6754       $updateClass: function(newClasses, oldClasses) {
6755         var toAdd = tokenDifference(newClasses, oldClasses);
6756         if (toAdd && toAdd.length) {
6757           $animate.addClass(this.$$element, toAdd);
6758         }
6759
6760         var toRemove = tokenDifference(oldClasses, newClasses);
6761         if (toRemove && toRemove.length) {
6762           $animate.removeClass(this.$$element, toRemove);
6763         }
6764       },
6765
6766       /**
6767        * Set a normalized attribute on the element in a way such that all directives
6768        * can share the attribute. This function properly handles boolean attributes.
6769        * @param {string} key Normalized key. (ie ngAttribute)
6770        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
6771        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
6772        *     Defaults to true.
6773        * @param {string=} attrName Optional none normalized name. Defaults to key.
6774        */
6775       $set: function(key, value, writeAttr, attrName) {
6776         // TODO: decide whether or not to throw an error if "class"
6777         //is set through this function since it may cause $updateClass to
6778         //become unstable.
6779
6780         var node = this.$$element[0],
6781             booleanKey = getBooleanAttrName(node, key),
6782             aliasedKey = getAliasedAttrName(node, key),
6783             observer = key,
6784             nodeName;
6785
6786         if (booleanKey) {
6787           this.$$element.prop(key, value);
6788           attrName = booleanKey;
6789         } else if (aliasedKey) {
6790           this[aliasedKey] = value;
6791           observer = aliasedKey;
6792         }
6793
6794         this[key] = value;
6795
6796         // translate normalized key to actual key
6797         if (attrName) {
6798           this.$attr[key] = attrName;
6799         } else {
6800           attrName = this.$attr[key];
6801           if (!attrName) {
6802             this.$attr[key] = attrName = snake_case(key, '-');
6803           }
6804         }
6805
6806         nodeName = nodeName_(this.$$element);
6807
6808         if ((nodeName === 'a' && key === 'href') ||
6809             (nodeName === 'img' && key === 'src')) {
6810           // sanitize a[href] and img[src] values
6811           this[key] = value = $$sanitizeUri(value, key === 'src');
6812         } else if (nodeName === 'img' && key === 'srcset') {
6813           // sanitize img[srcset] values
6814           var result = "";
6815
6816           // first check if there are spaces because it's not the same pattern
6817           var trimmedSrcset = trim(value);
6818           //                (   999x   ,|   999w   ,|   ,|,   )
6819           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
6820           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
6821
6822           // split srcset into tuple of uri and descriptor except for the last item
6823           var rawUris = trimmedSrcset.split(pattern);
6824
6825           // for each tuples
6826           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
6827           for (var i = 0; i < nbrUrisWith2parts; i++) {
6828             var innerIdx = i * 2;
6829             // sanitize the uri
6830             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
6831             // add the descriptor
6832             result += (" " + trim(rawUris[innerIdx + 1]));
6833           }
6834
6835           // split the last item into uri and descriptor
6836           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
6837
6838           // sanitize the last uri
6839           result += $$sanitizeUri(trim(lastTuple[0]), true);
6840
6841           // and add the last descriptor if any
6842           if (lastTuple.length === 2) {
6843             result += (" " + trim(lastTuple[1]));
6844           }
6845           this[key] = value = result;
6846         }
6847
6848         if (writeAttr !== false) {
6849           if (value === null || value === undefined) {
6850             this.$$element.removeAttr(attrName);
6851           } else {
6852             this.$$element.attr(attrName, value);
6853           }
6854         }
6855
6856         // fire observers
6857         var $$observers = this.$$observers;
6858         $$observers && forEach($$observers[observer], function(fn) {
6859           try {
6860             fn(value);
6861           } catch (e) {
6862             $exceptionHandler(e);
6863           }
6864         });
6865       },
6866
6867
6868       /**
6869        * @ngdoc method
6870        * @name $compile.directive.Attributes#$observe
6871        * @kind function
6872        *
6873        * @description
6874        * Observes an interpolated attribute.
6875        *
6876        * The observer function will be invoked once during the next `$digest` following
6877        * compilation. The observer is then invoked whenever the interpolated value
6878        * changes.
6879        *
6880        * @param {string} key Normalized key. (ie ngAttribute) .
6881        * @param {function(interpolatedValue)} fn Function that will be called whenever
6882                 the interpolated value of the attribute changes.
6883        *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
6884        * @returns {function()} Returns a deregistration function for this observer.
6885        */
6886       $observe: function(key, fn) {
6887         var attrs = this,
6888             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
6889             listeners = ($$observers[key] || ($$observers[key] = []));
6890
6891         listeners.push(fn);
6892         $rootScope.$evalAsync(function() {
6893           if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
6894             // no one registered attribute interpolation function, so lets call it manually
6895             fn(attrs[key]);
6896           }
6897         });
6898
6899         return function() {
6900           arrayRemove(listeners, fn);
6901         };
6902       }
6903     };
6904
6905
6906     function safeAddClass($element, className) {
6907       try {
6908         $element.addClass(className);
6909       } catch (e) {
6910         // ignore, since it means that we are trying to set class on
6911         // SVG element, where class name is read-only.
6912       }
6913     }
6914
6915
6916     var startSymbol = $interpolate.startSymbol(),
6917         endSymbol = $interpolate.endSymbol(),
6918         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
6919             ? identity
6920             : function denormalizeTemplate(template) {
6921               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
6922         },
6923         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
6924
6925     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
6926       var bindings = $element.data('$binding') || [];
6927
6928       if (isArray(binding)) {
6929         bindings = bindings.concat(binding);
6930       } else {
6931         bindings.push(binding);
6932       }
6933
6934       $element.data('$binding', bindings);
6935     } : noop;
6936
6937     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
6938       safeAddClass($element, 'ng-binding');
6939     } : noop;
6940
6941     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
6942       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
6943       $element.data(dataName, scope);
6944     } : noop;
6945
6946     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
6947       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
6948     } : noop;
6949
6950     return compile;
6951
6952     //================================
6953
6954     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
6955                         previousCompileContext) {
6956       if (!($compileNodes instanceof jqLite)) {
6957         // jquery always rewraps, whereas we need to preserve the original selector so that we can
6958         // modify it.
6959         $compileNodes = jqLite($compileNodes);
6960       }
6961       // We can not compile top level text elements since text nodes can be merged and we will
6962       // not be able to attach scope data to them, so we will wrap them in <span>
6963       forEach($compileNodes, function(node, index) {
6964         if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
6965           $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
6966         }
6967       });
6968       var compositeLinkFn =
6969               compileNodes($compileNodes, transcludeFn, $compileNodes,
6970                            maxPriority, ignoreDirective, previousCompileContext);
6971       compile.$$addScopeClass($compileNodes);
6972       var namespace = null;
6973       return function publicLinkFn(scope, cloneConnectFn, options) {
6974         assertArg(scope, 'scope');
6975
6976         options = options || {};
6977         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
6978           transcludeControllers = options.transcludeControllers,
6979           futureParentElement = options.futureParentElement;
6980
6981         // When `parentBoundTranscludeFn` is passed, it is a
6982         // `controllersBoundTransclude` function (it was previously passed
6983         // as `transclude` to directive.link) so we must unwrap it to get
6984         // its `boundTranscludeFn`
6985         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
6986           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
6987         }
6988
6989         if (!namespace) {
6990           namespace = detectNamespaceForChildElements(futureParentElement);
6991         }
6992         var $linkNode;
6993         if (namespace !== 'html') {
6994           // When using a directive with replace:true and templateUrl the $compileNodes
6995           // (or a child element inside of them)
6996           // might change, so we need to recreate the namespace adapted compileNodes
6997           // for call to the link function.
6998           // Note: This will already clone the nodes...
6999           $linkNode = jqLite(
7000             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7001           );
7002         } else if (cloneConnectFn) {
7003           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
7004           // and sometimes changes the structure of the DOM.
7005           $linkNode = JQLitePrototype.clone.call($compileNodes);
7006         } else {
7007           $linkNode = $compileNodes;
7008         }
7009
7010         if (transcludeControllers) {
7011           for (var controllerName in transcludeControllers) {
7012             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7013           }
7014         }
7015
7016         compile.$$addScopeInfo($linkNode, scope);
7017
7018         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7019         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7020         return $linkNode;
7021       };
7022     }
7023
7024     function detectNamespaceForChildElements(parentElement) {
7025       // TODO: Make this detect MathML as well...
7026       var node = parentElement && parentElement[0];
7027       if (!node) {
7028         return 'html';
7029       } else {
7030         return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7031       }
7032     }
7033
7034     /**
7035      * Compile function matches each node in nodeList against the directives. Once all directives
7036      * for a particular node are collected their compile functions are executed. The compile
7037      * functions return values - the linking functions - are combined into a composite linking
7038      * function, which is the a linking function for the node.
7039      *
7040      * @param {NodeList} nodeList an array of nodes or NodeList to compile
7041      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7042      *        scope argument is auto-generated to the new child of the transcluded parent scope.
7043      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7044      *        the rootElement must be set the jqLite collection of the compile root. This is
7045      *        needed so that the jqLite collection items can be replaced with widgets.
7046      * @param {number=} maxPriority Max directive priority.
7047      * @returns {Function} A composite linking function of all of the matched directives or null.
7048      */
7049     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7050                             previousCompileContext) {
7051       var linkFns = [],
7052           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7053
7054       for (var i = 0; i < nodeList.length; i++) {
7055         attrs = new Attributes();
7056
7057         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7058         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7059                                         ignoreDirective);
7060
7061         nodeLinkFn = (directives.length)
7062             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7063                                       null, [], [], previousCompileContext)
7064             : null;
7065
7066         if (nodeLinkFn && nodeLinkFn.scope) {
7067           compile.$$addScopeClass(attrs.$$element);
7068         }
7069
7070         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7071                       !(childNodes = nodeList[i].childNodes) ||
7072                       !childNodes.length)
7073             ? null
7074             : compileNodes(childNodes,
7075                  nodeLinkFn ? (
7076                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7077                      && nodeLinkFn.transclude) : transcludeFn);
7078
7079         if (nodeLinkFn || childLinkFn) {
7080           linkFns.push(i, nodeLinkFn, childLinkFn);
7081           linkFnFound = true;
7082           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7083         }
7084
7085         //use the previous context only for the first element in the virtual group
7086         previousCompileContext = null;
7087       }
7088
7089       // return a linking function if we have found anything, null otherwise
7090       return linkFnFound ? compositeLinkFn : null;
7091
7092       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7093         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7094         var stableNodeList;
7095
7096
7097         if (nodeLinkFnFound) {
7098           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7099           // offsets don't get screwed up
7100           var nodeListLength = nodeList.length;
7101           stableNodeList = new Array(nodeListLength);
7102
7103           // create a sparse array by only copying the elements which have a linkFn
7104           for (i = 0; i < linkFns.length; i+=3) {
7105             idx = linkFns[i];
7106             stableNodeList[idx] = nodeList[idx];
7107           }
7108         } else {
7109           stableNodeList = nodeList;
7110         }
7111
7112         for (i = 0, ii = linkFns.length; i < ii;) {
7113           node = stableNodeList[linkFns[i++]];
7114           nodeLinkFn = linkFns[i++];
7115           childLinkFn = linkFns[i++];
7116
7117           if (nodeLinkFn) {
7118             if (nodeLinkFn.scope) {
7119               childScope = scope.$new();
7120               compile.$$addScopeInfo(jqLite(node), childScope);
7121             } else {
7122               childScope = scope;
7123             }
7124
7125             if (nodeLinkFn.transcludeOnThisElement) {
7126               childBoundTranscludeFn = createBoundTranscludeFn(
7127                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
7128                   nodeLinkFn.elementTranscludeOnThisElement);
7129
7130             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7131               childBoundTranscludeFn = parentBoundTranscludeFn;
7132
7133             } else if (!parentBoundTranscludeFn && transcludeFn) {
7134               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7135
7136             } else {
7137               childBoundTranscludeFn = null;
7138             }
7139
7140             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7141
7142           } else if (childLinkFn) {
7143             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7144           }
7145         }
7146       }
7147     }
7148
7149     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
7150
7151       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7152
7153         if (!transcludedScope) {
7154           transcludedScope = scope.$new(false, containingScope);
7155           transcludedScope.$$transcluded = true;
7156         }
7157
7158         return transcludeFn(transcludedScope, cloneFn, {
7159           parentBoundTranscludeFn: previousBoundTranscludeFn,
7160           transcludeControllers: controllers,
7161           futureParentElement: futureParentElement
7162         });
7163       };
7164
7165       return boundTranscludeFn;
7166     }
7167
7168     /**
7169      * Looks for directives on the given node and adds them to the directive collection which is
7170      * sorted.
7171      *
7172      * @param node Node to search.
7173      * @param directives An array to which the directives are added to. This array is sorted before
7174      *        the function returns.
7175      * @param attrs The shared attrs object which is used to populate the normalized attributes.
7176      * @param {number=} maxPriority Max directive priority.
7177      */
7178     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7179       var nodeType = node.nodeType,
7180           attrsMap = attrs.$attr,
7181           match,
7182           className;
7183
7184       switch (nodeType) {
7185         case NODE_TYPE_ELEMENT: /* Element */
7186           // use the node name: <directive>
7187           addDirective(directives,
7188               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7189
7190           // iterate over the attributes
7191           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7192                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7193             var attrStartName = false;
7194             var attrEndName = false;
7195
7196             attr = nAttrs[j];
7197             name = attr.name;
7198             value = trim(attr.value);
7199
7200             // support ngAttr attribute binding
7201             ngAttrName = directiveNormalize(name);
7202             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7203               name = name.replace(PREFIX_REGEXP, '')
7204                 .substr(8).replace(/_(.)/g, function(match, letter) {
7205                   return letter.toUpperCase();
7206                 });
7207             }
7208
7209             var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
7210             if (directiveIsMultiElement(directiveNName)) {
7211               if (ngAttrName === directiveNName + 'Start') {
7212                 attrStartName = name;
7213                 attrEndName = name.substr(0, name.length - 5) + 'end';
7214                 name = name.substr(0, name.length - 6);
7215               }
7216             }
7217
7218             nName = directiveNormalize(name.toLowerCase());
7219             attrsMap[nName] = name;
7220             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7221                 attrs[nName] = value;
7222                 if (getBooleanAttrName(node, nName)) {
7223                   attrs[nName] = true; // presence means true
7224                 }
7225             }
7226             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7227             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7228                           attrEndName);
7229           }
7230
7231           // use class as directive
7232           className = node.className;
7233           if (isObject(className)) {
7234               // Maybe SVGAnimatedString
7235               className = className.animVal;
7236           }
7237           if (isString(className) && className !== '') {
7238             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7239               nName = directiveNormalize(match[2]);
7240               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7241                 attrs[nName] = trim(match[3]);
7242               }
7243               className = className.substr(match.index + match[0].length);
7244             }
7245           }
7246           break;
7247         case NODE_TYPE_TEXT: /* Text Node */
7248           addTextInterpolateDirective(directives, node.nodeValue);
7249           break;
7250         case NODE_TYPE_COMMENT: /* Comment */
7251           try {
7252             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7253             if (match) {
7254               nName = directiveNormalize(match[1]);
7255               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7256                 attrs[nName] = trim(match[2]);
7257               }
7258             }
7259           } catch (e) {
7260             // turns out that under some circumstances IE9 throws errors when one attempts to read
7261             // comment's node value.
7262             // Just ignore it and continue. (Can't seem to reproduce in test case.)
7263           }
7264           break;
7265       }
7266
7267       directives.sort(byPriority);
7268       return directives;
7269     }
7270
7271     /**
7272      * Given a node with an directive-start it collects all of the siblings until it finds
7273      * directive-end.
7274      * @param node
7275      * @param attrStart
7276      * @param attrEnd
7277      * @returns {*}
7278      */
7279     function groupScan(node, attrStart, attrEnd) {
7280       var nodes = [];
7281       var depth = 0;
7282       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7283         do {
7284           if (!node) {
7285             throw $compileMinErr('uterdir',
7286                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7287                       attrStart, attrEnd);
7288           }
7289           if (node.nodeType == NODE_TYPE_ELEMENT) {
7290             if (node.hasAttribute(attrStart)) depth++;
7291             if (node.hasAttribute(attrEnd)) depth--;
7292           }
7293           nodes.push(node);
7294           node = node.nextSibling;
7295         } while (depth > 0);
7296       } else {
7297         nodes.push(node);
7298       }
7299
7300       return jqLite(nodes);
7301     }
7302
7303     /**
7304      * Wrapper for linking function which converts normal linking function into a grouped
7305      * linking function.
7306      * @param linkFn
7307      * @param attrStart
7308      * @param attrEnd
7309      * @returns {Function}
7310      */
7311     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7312       return function(scope, element, attrs, controllers, transcludeFn) {
7313         element = groupScan(element[0], attrStart, attrEnd);
7314         return linkFn(scope, element, attrs, controllers, transcludeFn);
7315       };
7316     }
7317
7318     /**
7319      * Once the directives have been collected, their compile functions are executed. This method
7320      * is responsible for inlining directive templates as well as terminating the application
7321      * of the directives if the terminal directive has been reached.
7322      *
7323      * @param {Array} directives Array of collected directives to execute their compile function.
7324      *        this needs to be pre-sorted by priority order.
7325      * @param {Node} compileNode The raw DOM node to apply the compile functions to
7326      * @param {Object} templateAttrs The shared attribute function
7327      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7328      *                                                  scope argument is auto-generated to the new
7329      *                                                  child of the transcluded parent scope.
7330      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
7331      *                              argument has the root jqLite array so that we can replace nodes
7332      *                              on it.
7333      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
7334      *                                           compiling the transclusion.
7335      * @param {Array.<Function>} preLinkFns
7336      * @param {Array.<Function>} postLinkFns
7337      * @param {Object} previousCompileContext Context used for previous compilation of the current
7338      *                                        node
7339      * @returns {Function} linkFn
7340      */
7341     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
7342                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
7343                                    previousCompileContext) {
7344       previousCompileContext = previousCompileContext || {};
7345
7346       var terminalPriority = -Number.MAX_VALUE,
7347           newScopeDirective,
7348           controllerDirectives = previousCompileContext.controllerDirectives,
7349           controllers,
7350           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
7351           templateDirective = previousCompileContext.templateDirective,
7352           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
7353           hasTranscludeDirective = false,
7354           hasTemplate = false,
7355           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
7356           $compileNode = templateAttrs.$$element = jqLite(compileNode),
7357           directive,
7358           directiveName,
7359           $template,
7360           replaceDirective = originalReplaceDirective,
7361           childTranscludeFn = transcludeFn,
7362           linkFn,
7363           directiveValue;
7364
7365       // executes all directives on the current element
7366       for (var i = 0, ii = directives.length; i < ii; i++) {
7367         directive = directives[i];
7368         var attrStart = directive.$$start;
7369         var attrEnd = directive.$$end;
7370
7371         // collect multiblock sections
7372         if (attrStart) {
7373           $compileNode = groupScan(compileNode, attrStart, attrEnd);
7374         }
7375         $template = undefined;
7376
7377         if (terminalPriority > directive.priority) {
7378           break; // prevent further processing of directives
7379         }
7380
7381         if (directiveValue = directive.scope) {
7382
7383           // skip the check for directives with async templates, we'll check the derived sync
7384           // directive when the template arrives
7385           if (!directive.templateUrl) {
7386             if (isObject(directiveValue)) {
7387               // This directive is trying to add an isolated scope.
7388               // Check that there is no scope of any kind already
7389               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
7390                                 directive, $compileNode);
7391               newIsolateScopeDirective = directive;
7392             } else {
7393               // This directive is trying to add a child scope.
7394               // Check that there is no isolated scope already
7395               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
7396                                 $compileNode);
7397             }
7398           }
7399
7400           newScopeDirective = newScopeDirective || directive;
7401         }
7402
7403         directiveName = directive.name;
7404
7405         if (!directive.templateUrl && directive.controller) {
7406           directiveValue = directive.controller;
7407           controllerDirectives = controllerDirectives || {};
7408           assertNoDuplicate("'" + directiveName + "' controller",
7409               controllerDirectives[directiveName], directive, $compileNode);
7410           controllerDirectives[directiveName] = directive;
7411         }
7412
7413         if (directiveValue = directive.transclude) {
7414           hasTranscludeDirective = true;
7415
7416           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
7417           // This option should only be used by directives that know how to safely handle element transclusion,
7418           // where the transcluded nodes are added or replaced after linking.
7419           if (!directive.$$tlb) {
7420             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
7421             nonTlbTranscludeDirective = directive;
7422           }
7423
7424           if (directiveValue == 'element') {
7425             hasElementTranscludeDirective = true;
7426             terminalPriority = directive.priority;
7427             $template = $compileNode;
7428             $compileNode = templateAttrs.$$element =
7429                 jqLite(document.createComment(' ' + directiveName + ': ' +
7430                                               templateAttrs[directiveName] + ' '));
7431             compileNode = $compileNode[0];
7432             replaceWith(jqCollection, sliceArgs($template), compileNode);
7433
7434             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
7435                                         replaceDirective && replaceDirective.name, {
7436                                           // Don't pass in:
7437                                           // - controllerDirectives - otherwise we'll create duplicates controllers
7438                                           // - newIsolateScopeDirective or templateDirective - combining templates with
7439                                           //   element transclusion doesn't make sense.
7440                                           //
7441                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
7442                                           // on the same element more than once.
7443                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
7444                                         });
7445           } else {
7446             $template = jqLite(jqLiteClone(compileNode)).contents();
7447             $compileNode.empty(); // clear contents
7448             childTranscludeFn = compile($template, transcludeFn);
7449           }
7450         }
7451
7452         if (directive.template) {
7453           hasTemplate = true;
7454           assertNoDuplicate('template', templateDirective, directive, $compileNode);
7455           templateDirective = directive;
7456
7457           directiveValue = (isFunction(directive.template))
7458               ? directive.template($compileNode, templateAttrs)
7459               : directive.template;
7460
7461           directiveValue = denormalizeTemplate(directiveValue);
7462
7463           if (directive.replace) {
7464             replaceDirective = directive;
7465             if (jqLiteIsTextNode(directiveValue)) {
7466               $template = [];
7467             } else {
7468               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
7469             }
7470             compileNode = $template[0];
7471
7472             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7473               throw $compileMinErr('tplrt',
7474                   "Template for directive '{0}' must have exactly one root element. {1}",
7475                   directiveName, '');
7476             }
7477
7478             replaceWith(jqCollection, $compileNode, compileNode);
7479
7480             var newTemplateAttrs = {$attr: {}};
7481
7482             // combine directives from the original node and from the template:
7483             // - take the array of directives for this element
7484             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
7485             // - collect directives from the template and sort them by priority
7486             // - combine directives as: processed + template + unprocessed
7487             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
7488             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
7489
7490             if (newIsolateScopeDirective) {
7491               markDirectivesAsIsolate(templateDirectives);
7492             }
7493             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
7494             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
7495
7496             ii = directives.length;
7497           } else {
7498             $compileNode.html(directiveValue);
7499           }
7500         }
7501
7502         if (directive.templateUrl) {
7503           hasTemplate = true;
7504           assertNoDuplicate('template', templateDirective, directive, $compileNode);
7505           templateDirective = directive;
7506
7507           if (directive.replace) {
7508             replaceDirective = directive;
7509           }
7510
7511           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
7512               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
7513                 controllerDirectives: controllerDirectives,
7514                 newIsolateScopeDirective: newIsolateScopeDirective,
7515                 templateDirective: templateDirective,
7516                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
7517               });
7518           ii = directives.length;
7519         } else if (directive.compile) {
7520           try {
7521             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
7522             if (isFunction(linkFn)) {
7523               addLinkFns(null, linkFn, attrStart, attrEnd);
7524             } else if (linkFn) {
7525               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
7526             }
7527           } catch (e) {
7528             $exceptionHandler(e, startingTag($compileNode));
7529           }
7530         }
7531
7532         if (directive.terminal) {
7533           nodeLinkFn.terminal = true;
7534           terminalPriority = Math.max(terminalPriority, directive.priority);
7535         }
7536
7537       }
7538
7539       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
7540       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
7541       nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
7542       nodeLinkFn.templateOnThisElement = hasTemplate;
7543       nodeLinkFn.transclude = childTranscludeFn;
7544
7545       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
7546
7547       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
7548       return nodeLinkFn;
7549
7550       ////////////////////
7551
7552       function addLinkFns(pre, post, attrStart, attrEnd) {
7553         if (pre) {
7554           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
7555           pre.require = directive.require;
7556           pre.directiveName = directiveName;
7557           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7558             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
7559           }
7560           preLinkFns.push(pre);
7561         }
7562         if (post) {
7563           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
7564           post.require = directive.require;
7565           post.directiveName = directiveName;
7566           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7567             post = cloneAndAnnotateFn(post, {isolateScope: true});
7568           }
7569           postLinkFns.push(post);
7570         }
7571       }
7572
7573
7574       function getControllers(directiveName, require, $element, elementControllers) {
7575         var value, retrievalMethod = 'data', optional = false;
7576         var $searchElement = $element;
7577         var match;
7578         if (isString(require)) {
7579           match = require.match(REQUIRE_PREFIX_REGEXP);
7580           require = require.substring(match[0].length);
7581
7582           if (match[3]) {
7583             if (match[1]) match[3] = null;
7584             else match[1] = match[3];
7585           }
7586           if (match[1] === '^') {
7587             retrievalMethod = 'inheritedData';
7588           } else if (match[1] === '^^') {
7589             retrievalMethod = 'inheritedData';
7590             $searchElement = $element.parent();
7591           }
7592           if (match[2] === '?') {
7593             optional = true;
7594           }
7595
7596           value = null;
7597
7598           if (elementControllers && retrievalMethod === 'data') {
7599             if (value = elementControllers[require]) {
7600               value = value.instance;
7601             }
7602           }
7603           value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
7604
7605           if (!value && !optional) {
7606             throw $compileMinErr('ctreq',
7607                 "Controller '{0}', required by directive '{1}', can't be found!",
7608                 require, directiveName);
7609           }
7610           return value || null;
7611         } else if (isArray(require)) {
7612           value = [];
7613           forEach(require, function(require) {
7614             value.push(getControllers(directiveName, require, $element, elementControllers));
7615           });
7616         }
7617         return value;
7618       }
7619
7620
7621       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
7622         var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
7623             attrs;
7624
7625         if (compileNode === linkNode) {
7626           attrs = templateAttrs;
7627           $element = templateAttrs.$$element;
7628         } else {
7629           $element = jqLite(linkNode);
7630           attrs = new Attributes($element, templateAttrs);
7631         }
7632
7633         if (newIsolateScopeDirective) {
7634           isolateScope = scope.$new(true);
7635         }
7636
7637         if (boundTranscludeFn) {
7638           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
7639           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
7640           transcludeFn = controllersBoundTransclude;
7641           transcludeFn.$$boundTransclude = boundTranscludeFn;
7642         }
7643
7644         if (controllerDirectives) {
7645           // TODO: merge `controllers` and `elementControllers` into single object.
7646           controllers = {};
7647           elementControllers = {};
7648           forEach(controllerDirectives, function(directive) {
7649             var locals = {
7650               $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
7651               $element: $element,
7652               $attrs: attrs,
7653               $transclude: transcludeFn
7654             }, controllerInstance;
7655
7656             controller = directive.controller;
7657             if (controller == '@') {
7658               controller = attrs[directive.name];
7659             }
7660
7661             controllerInstance = $controller(controller, locals, true, directive.controllerAs);
7662
7663             // For directives with element transclusion the element is a comment,
7664             // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
7665             // clean up (http://bugs.jquery.com/ticket/8335).
7666             // Instead, we save the controllers for the element in a local hash and attach to .data
7667             // later, once we have the actual element.
7668             elementControllers[directive.name] = controllerInstance;
7669             if (!hasElementTranscludeDirective) {
7670               $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
7671             }
7672
7673             controllers[directive.name] = controllerInstance;
7674           });
7675         }
7676
7677         if (newIsolateScopeDirective) {
7678           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
7679               templateDirective === newIsolateScopeDirective.$$originalDirective)));
7680           compile.$$addScopeClass($element, true);
7681
7682           var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name];
7683           var isolateBindingContext = isolateScope;
7684           if (isolateScopeController && isolateScopeController.identifier &&
7685               newIsolateScopeDirective.bindToController === true) {
7686             isolateBindingContext = isolateScopeController.instance;
7687           }
7688
7689           forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) {
7690             var attrName = definition.attrName,
7691                 optional = definition.optional,
7692                 mode = definition.mode, // @, =, or &
7693                 lastValue,
7694                 parentGet, parentSet, compare;
7695
7696             switch (mode) {
7697
7698               case '@':
7699                 attrs.$observe(attrName, function(value) {
7700                   isolateBindingContext[scopeName] = value;
7701                 });
7702                 attrs.$$observers[attrName].$$scope = scope;
7703                 if (attrs[attrName]) {
7704                   // If the attribute has been provided then we trigger an interpolation to ensure
7705                   // the value is there for use in the link fn
7706                   isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
7707                 }
7708                 break;
7709
7710               case '=':
7711                 if (optional && !attrs[attrName]) {
7712                   return;
7713                 }
7714                 parentGet = $parse(attrs[attrName]);
7715                 if (parentGet.literal) {
7716                   compare = equals;
7717                 } else {
7718                   compare = function(a, b) { return a === b || (a !== a && b !== b); };
7719                 }
7720                 parentSet = parentGet.assign || function() {
7721                   // reset the change, or we will throw this exception on every $digest
7722                   lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7723                   throw $compileMinErr('nonassign',
7724                       "Expression '{0}' used with directive '{1}' is non-assignable!",
7725                       attrs[attrName], newIsolateScopeDirective.name);
7726                 };
7727                 lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7728                 var parentValueWatch = function parentValueWatch(parentValue) {
7729                   if (!compare(parentValue, isolateBindingContext[scopeName])) {
7730                     // we are out of sync and need to copy
7731                     if (!compare(parentValue, lastValue)) {
7732                       // parent changed and it has precedence
7733                       isolateBindingContext[scopeName] = parentValue;
7734                     } else {
7735                       // if the parent can be assigned then do so
7736                       parentSet(scope, parentValue = isolateBindingContext[scopeName]);
7737                     }
7738                   }
7739                   return lastValue = parentValue;
7740                 };
7741                 parentValueWatch.$stateful = true;
7742                 var unwatch;
7743                 if (definition.collection) {
7744                   unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
7745                 } else {
7746                   unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
7747                 }
7748                 isolateScope.$on('$destroy', unwatch);
7749                 break;
7750
7751               case '&':
7752                 parentGet = $parse(attrs[attrName]);
7753                 isolateBindingContext[scopeName] = function(locals) {
7754                   return parentGet(scope, locals);
7755                 };
7756                 break;
7757             }
7758           });
7759         }
7760         if (controllers) {
7761           forEach(controllers, function(controller) {
7762             controller();
7763           });
7764           controllers = null;
7765         }
7766
7767         // PRELINKING
7768         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
7769           linkFn = preLinkFns[i];
7770           invokeLinkFn(linkFn,
7771               linkFn.isolateScope ? isolateScope : scope,
7772               $element,
7773               attrs,
7774               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7775               transcludeFn
7776           );
7777         }
7778
7779         // RECURSION
7780         // We only pass the isolate scope, if the isolate directive has a template,
7781         // otherwise the child elements do not belong to the isolate directive.
7782         var scopeToChild = scope;
7783         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
7784           scopeToChild = isolateScope;
7785         }
7786         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
7787
7788         // POSTLINKING
7789         for (i = postLinkFns.length - 1; i >= 0; i--) {
7790           linkFn = postLinkFns[i];
7791           invokeLinkFn(linkFn,
7792               linkFn.isolateScope ? isolateScope : scope,
7793               $element,
7794               attrs,
7795               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7796               transcludeFn
7797           );
7798         }
7799
7800         // This is the function that is injected as `$transclude`.
7801         // Note: all arguments are optional!
7802         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
7803           var transcludeControllers;
7804
7805           // No scope passed in:
7806           if (!isScope(scope)) {
7807             futureParentElement = cloneAttachFn;
7808             cloneAttachFn = scope;
7809             scope = undefined;
7810           }
7811
7812           if (hasElementTranscludeDirective) {
7813             transcludeControllers = elementControllers;
7814           }
7815           if (!futureParentElement) {
7816             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
7817           }
7818           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
7819         }
7820       }
7821     }
7822
7823     function markDirectivesAsIsolate(directives) {
7824       // mark all directives as needing isolate scope.
7825       for (var j = 0, jj = directives.length; j < jj; j++) {
7826         directives[j] = inherit(directives[j], {$$isolateScope: true});
7827       }
7828     }
7829
7830     /**
7831      * looks up the directive and decorates it with exception handling and proper parameters. We
7832      * call this the boundDirective.
7833      *
7834      * @param {string} name name of the directive to look up.
7835      * @param {string} location The directive must be found in specific format.
7836      *   String containing any of theses characters:
7837      *
7838      *   * `E`: element name
7839      *   * `A': attribute
7840      *   * `C`: class
7841      *   * `M`: comment
7842      * @returns {boolean} true if directive was added.
7843      */
7844     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
7845                           endAttrName) {
7846       if (name === ignoreDirective) return null;
7847       var match = null;
7848       if (hasDirectives.hasOwnProperty(name)) {
7849         for (var directive, directives = $injector.get(name + Suffix),
7850             i = 0, ii = directives.length; i < ii; i++) {
7851           try {
7852             directive = directives[i];
7853             if ((maxPriority === undefined || maxPriority > directive.priority) &&
7854                  directive.restrict.indexOf(location) != -1) {
7855               if (startAttrName) {
7856                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
7857               }
7858               tDirectives.push(directive);
7859               match = directive;
7860             }
7861           } catch (e) { $exceptionHandler(e); }
7862         }
7863       }
7864       return match;
7865     }
7866
7867
7868     /**
7869      * looks up the directive and returns true if it is a multi-element directive,
7870      * and therefore requires DOM nodes between -start and -end markers to be grouped
7871      * together.
7872      *
7873      * @param {string} name name of the directive to look up.
7874      * @returns true if directive was registered as multi-element.
7875      */
7876     function directiveIsMultiElement(name) {
7877       if (hasDirectives.hasOwnProperty(name)) {
7878         for (var directive, directives = $injector.get(name + Suffix),
7879             i = 0, ii = directives.length; i < ii; i++) {
7880           directive = directives[i];
7881           if (directive.multiElement) {
7882             return true;
7883           }
7884         }
7885       }
7886       return false;
7887     }
7888
7889     /**
7890      * When the element is replaced with HTML template then the new attributes
7891      * on the template need to be merged with the existing attributes in the DOM.
7892      * The desired effect is to have both of the attributes present.
7893      *
7894      * @param {object} dst destination attributes (original DOM)
7895      * @param {object} src source attributes (from the directive template)
7896      */
7897     function mergeTemplateAttributes(dst, src) {
7898       var srcAttr = src.$attr,
7899           dstAttr = dst.$attr,
7900           $element = dst.$$element;
7901
7902       // reapply the old attributes to the new element
7903       forEach(dst, function(value, key) {
7904         if (key.charAt(0) != '$') {
7905           if (src[key] && src[key] !== value) {
7906             value += (key === 'style' ? ';' : ' ') + src[key];
7907           }
7908           dst.$set(key, value, true, srcAttr[key]);
7909         }
7910       });
7911
7912       // copy the new attributes on the old attrs object
7913       forEach(src, function(value, key) {
7914         if (key == 'class') {
7915           safeAddClass($element, value);
7916           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
7917         } else if (key == 'style') {
7918           $element.attr('style', $element.attr('style') + ';' + value);
7919           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
7920           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
7921           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
7922           // have an attribute like "has-own-property" or "data-has-own-property", etc.
7923         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
7924           dst[key] = value;
7925           dstAttr[key] = srcAttr[key];
7926         }
7927       });
7928     }
7929
7930
7931     function compileTemplateUrl(directives, $compileNode, tAttrs,
7932         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
7933       var linkQueue = [],
7934           afterTemplateNodeLinkFn,
7935           afterTemplateChildLinkFn,
7936           beforeTemplateCompileNode = $compileNode[0],
7937           origAsyncDirective = directives.shift(),
7938           derivedSyncDirective = inherit(origAsyncDirective, {
7939             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
7940           }),
7941           templateUrl = (isFunction(origAsyncDirective.templateUrl))
7942               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
7943               : origAsyncDirective.templateUrl,
7944           templateNamespace = origAsyncDirective.templateNamespace;
7945
7946       $compileNode.empty();
7947
7948       $templateRequest(templateUrl)
7949         .then(function(content) {
7950           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
7951
7952           content = denormalizeTemplate(content);
7953
7954           if (origAsyncDirective.replace) {
7955             if (jqLiteIsTextNode(content)) {
7956               $template = [];
7957             } else {
7958               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
7959             }
7960             compileNode = $template[0];
7961
7962             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7963               throw $compileMinErr('tplrt',
7964                   "Template for directive '{0}' must have exactly one root element. {1}",
7965                   origAsyncDirective.name, templateUrl);
7966             }
7967
7968             tempTemplateAttrs = {$attr: {}};
7969             replaceWith($rootElement, $compileNode, compileNode);
7970             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
7971
7972             if (isObject(origAsyncDirective.scope)) {
7973               markDirectivesAsIsolate(templateDirectives);
7974             }
7975             directives = templateDirectives.concat(directives);
7976             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
7977           } else {
7978             compileNode = beforeTemplateCompileNode;
7979             $compileNode.html(content);
7980           }
7981
7982           directives.unshift(derivedSyncDirective);
7983
7984           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
7985               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
7986               previousCompileContext);
7987           forEach($rootElement, function(node, i) {
7988             if (node == compileNode) {
7989               $rootElement[i] = $compileNode[0];
7990             }
7991           });
7992           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
7993
7994           while (linkQueue.length) {
7995             var scope = linkQueue.shift(),
7996                 beforeTemplateLinkNode = linkQueue.shift(),
7997                 linkRootElement = linkQueue.shift(),
7998                 boundTranscludeFn = linkQueue.shift(),
7999                 linkNode = $compileNode[0];
8000
8001             if (scope.$$destroyed) continue;
8002
8003             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8004               var oldClasses = beforeTemplateLinkNode.className;
8005
8006               if (!(previousCompileContext.hasElementTranscludeDirective &&
8007                   origAsyncDirective.replace)) {
8008                 // it was cloned therefore we have to clone as well.
8009                 linkNode = jqLiteClone(compileNode);
8010               }
8011               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8012
8013               // Copy in CSS classes from original node
8014               safeAddClass(jqLite(linkNode), oldClasses);
8015             }
8016             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8017               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8018             } else {
8019               childBoundTranscludeFn = boundTranscludeFn;
8020             }
8021             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8022               childBoundTranscludeFn);
8023           }
8024           linkQueue = null;
8025         });
8026
8027       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8028         var childBoundTranscludeFn = boundTranscludeFn;
8029         if (scope.$$destroyed) return;
8030         if (linkQueue) {
8031           linkQueue.push(scope,
8032                          node,
8033                          rootElement,
8034                          childBoundTranscludeFn);
8035         } else {
8036           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8037             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8038           }
8039           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8040         }
8041       };
8042     }
8043
8044
8045     /**
8046      * Sorting function for bound directives.
8047      */
8048     function byPriority(a, b) {
8049       var diff = b.priority - a.priority;
8050       if (diff !== 0) return diff;
8051       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8052       return a.index - b.index;
8053     }
8054
8055
8056     function assertNoDuplicate(what, previousDirective, directive, element) {
8057       if (previousDirective) {
8058         throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
8059             previousDirective.name, directive.name, what, startingTag(element));
8060       }
8061     }
8062
8063
8064     function addTextInterpolateDirective(directives, text) {
8065       var interpolateFn = $interpolate(text, true);
8066       if (interpolateFn) {
8067         directives.push({
8068           priority: 0,
8069           compile: function textInterpolateCompileFn(templateNode) {
8070             var templateNodeParent = templateNode.parent(),
8071                 hasCompileParent = !!templateNodeParent.length;
8072
8073             // When transcluding a template that has bindings in the root
8074             // we don't have a parent and thus need to add the class during linking fn.
8075             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8076
8077             return function textInterpolateLinkFn(scope, node) {
8078               var parent = node.parent();
8079               if (!hasCompileParent) compile.$$addBindingClass(parent);
8080               compile.$$addBindingInfo(parent, interpolateFn.expressions);
8081               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8082                 node[0].nodeValue = value;
8083               });
8084             };
8085           }
8086         });
8087       }
8088     }
8089
8090
8091     function wrapTemplate(type, template) {
8092       type = lowercase(type || 'html');
8093       switch (type) {
8094       case 'svg':
8095       case 'math':
8096         var wrapper = document.createElement('div');
8097         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8098         return wrapper.childNodes[0].childNodes;
8099       default:
8100         return template;
8101       }
8102     }
8103
8104
8105     function getTrustedContext(node, attrNormalizedName) {
8106       if (attrNormalizedName == "srcdoc") {
8107         return $sce.HTML;
8108       }
8109       var tag = nodeName_(node);
8110       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8111       if (attrNormalizedName == "xlinkHref" ||
8112           (tag == "form" && attrNormalizedName == "action") ||
8113           (tag != "img" && (attrNormalizedName == "src" ||
8114                             attrNormalizedName == "ngSrc"))) {
8115         return $sce.RESOURCE_URL;
8116       }
8117     }
8118
8119
8120     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8121       var trustedContext = getTrustedContext(node, name);
8122       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8123
8124       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8125
8126       // no interpolation found -> ignore
8127       if (!interpolateFn) return;
8128
8129
8130       if (name === "multiple" && nodeName_(node) === "select") {
8131         throw $compileMinErr("selmulti",
8132             "Binding to the 'multiple' attribute is not supported. Element: {0}",
8133             startingTag(node));
8134       }
8135
8136       directives.push({
8137         priority: 100,
8138         compile: function() {
8139             return {
8140               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8141                 var $$observers = (attr.$$observers || (attr.$$observers = {}));
8142
8143                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8144                   throw $compileMinErr('nodomevents',
8145                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8146                           "ng- versions (such as ng-click instead of onclick) instead.");
8147                 }
8148
8149                 // If the attribute has changed since last $interpolate()ed
8150                 var newValue = attr[name];
8151                 if (newValue !== value) {
8152                   // we need to interpolate again since the attribute value has been updated
8153                   // (e.g. by another directive's compile function)
8154                   // ensure unset/empty values make interpolateFn falsy
8155                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8156                   value = newValue;
8157                 }
8158
8159                 // if attribute was updated so that there is no interpolation going on we don't want to
8160                 // register any observers
8161                 if (!interpolateFn) return;
8162
8163                 // initialize attr object so that it's ready in case we need the value for isolate
8164                 // scope initialization, otherwise the value would not be available from isolate
8165                 // directive's linking fn during linking phase
8166                 attr[name] = interpolateFn(scope);
8167
8168                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8169                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
8170                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8171                     //special case for class attribute addition + removal
8172                     //so that class changes can tap into the animation
8173                     //hooks provided by the $animate service. Be sure to
8174                     //skip animations when the first digest occurs (when
8175                     //both the new and the old values are the same) since
8176                     //the CSS classes are the non-interpolated values
8177                     if (name === 'class' && newValue != oldValue) {
8178                       attr.$updateClass(newValue, oldValue);
8179                     } else {
8180                       attr.$set(name, newValue);
8181                     }
8182                   });
8183               }
8184             };
8185           }
8186       });
8187     }
8188
8189
8190     /**
8191      * This is a special jqLite.replaceWith, which can replace items which
8192      * have no parents, provided that the containing jqLite collection is provided.
8193      *
8194      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8195      *                               in the root of the tree.
8196      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8197      *                                  the shell, but replace its DOM node reference.
8198      * @param {Node} newNode The new DOM node.
8199      */
8200     function replaceWith($rootElement, elementsToRemove, newNode) {
8201       var firstElementToRemove = elementsToRemove[0],
8202           removeCount = elementsToRemove.length,
8203           parent = firstElementToRemove.parentNode,
8204           i, ii;
8205
8206       if ($rootElement) {
8207         for (i = 0, ii = $rootElement.length; i < ii; i++) {
8208           if ($rootElement[i] == firstElementToRemove) {
8209             $rootElement[i++] = newNode;
8210             for (var j = i, j2 = j + removeCount - 1,
8211                      jj = $rootElement.length;
8212                  j < jj; j++, j2++) {
8213               if (j2 < jj) {
8214                 $rootElement[j] = $rootElement[j2];
8215               } else {
8216                 delete $rootElement[j];
8217               }
8218             }
8219             $rootElement.length -= removeCount - 1;
8220
8221             // If the replaced element is also the jQuery .context then replace it
8222             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8223             // http://api.jquery.com/context/
8224             if ($rootElement.context === firstElementToRemove) {
8225               $rootElement.context = newNode;
8226             }
8227             break;
8228           }
8229         }
8230       }
8231
8232       if (parent) {
8233         parent.replaceChild(newNode, firstElementToRemove);
8234       }
8235
8236       // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8237       var fragment = document.createDocumentFragment();
8238       fragment.appendChild(firstElementToRemove);
8239
8240       // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8241       // data here because there's no public interface in jQuery to do that and copying over
8242       // event listeners (which is the main use of private data) wouldn't work anyway.
8243       jqLite(newNode).data(jqLite(firstElementToRemove).data());
8244
8245       // Remove data of the replaced element. We cannot just call .remove()
8246       // on the element it since that would deallocate scope that is needed
8247       // for the new node. Instead, remove the data "manually".
8248       if (!jQuery) {
8249         delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8250       } else {
8251         // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8252         // the replaced element. The cleanData version monkey-patched by Angular would cause
8253         // the scope to be trashed and we do need the very same scope to work with the new
8254         // element. However, we cannot just cache the non-patched version and use it here as
8255         // that would break if another library patches the method after Angular does (one
8256         // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8257         // skipped this one time.
8258         skipDestroyOnNextJQueryCleanData = true;
8259         jQuery.cleanData([firstElementToRemove]);
8260       }
8261
8262       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8263         var element = elementsToRemove[k];
8264         jqLite(element).remove(); // must do this way to clean up expando
8265         fragment.appendChild(element);
8266         delete elementsToRemove[k];
8267       }
8268
8269       elementsToRemove[0] = newNode;
8270       elementsToRemove.length = 1;
8271     }
8272
8273
8274     function cloneAndAnnotateFn(fn, annotation) {
8275       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8276     }
8277
8278
8279     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8280       try {
8281         linkFn(scope, $element, attrs, controllers, transcludeFn);
8282       } catch (e) {
8283         $exceptionHandler(e, startingTag($element));
8284       }
8285     }
8286   }];
8287 }
8288
8289 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8290 /**
8291  * Converts all accepted directives format into proper directive name.
8292  * @param name Name to normalize
8293  */
8294 function directiveNormalize(name) {
8295   return camelCase(name.replace(PREFIX_REGEXP, ''));
8296 }
8297
8298 /**
8299  * @ngdoc type
8300  * @name $compile.directive.Attributes
8301  *
8302  * @description
8303  * A shared object between directive compile / linking functions which contains normalized DOM
8304  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
8305  * needed since all of these are treated as equivalent in Angular:
8306  *
8307  * ```
8308  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
8309  * ```
8310  */
8311
8312 /**
8313  * @ngdoc property
8314  * @name $compile.directive.Attributes#$attr
8315  *
8316  * @description
8317  * A map of DOM element attribute names to the normalized name. This is
8318  * needed to do reverse lookup from normalized name back to actual name.
8319  */
8320
8321
8322 /**
8323  * @ngdoc method
8324  * @name $compile.directive.Attributes#$set
8325  * @kind function
8326  *
8327  * @description
8328  * Set DOM element attribute value.
8329  *
8330  *
8331  * @param {string} name Normalized element attribute name of the property to modify. The name is
8332  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
8333  *          property to the original name.
8334  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
8335  */
8336
8337
8338
8339 /**
8340  * Closure compiler type information
8341  */
8342
8343 function nodesetLinkingFn(
8344   /* angular.Scope */ scope,
8345   /* NodeList */ nodeList,
8346   /* Element */ rootElement,
8347   /* function(Function) */ boundTranscludeFn
8348 ) {}
8349
8350 function directiveLinkingFn(
8351   /* nodesetLinkingFn */ nodesetLinkingFn,
8352   /* angular.Scope */ scope,
8353   /* Node */ node,
8354   /* Element */ rootElement,
8355   /* function(Function) */ boundTranscludeFn
8356 ) {}
8357
8358 function tokenDifference(str1, str2) {
8359   var values = '',
8360       tokens1 = str1.split(/\s+/),
8361       tokens2 = str2.split(/\s+/);
8362
8363   outer:
8364   for (var i = 0; i < tokens1.length; i++) {
8365     var token = tokens1[i];
8366     for (var j = 0; j < tokens2.length; j++) {
8367       if (token == tokens2[j]) continue outer;
8368     }
8369     values += (values.length > 0 ? ' ' : '') + token;
8370   }
8371   return values;
8372 }
8373
8374 function removeComments(jqNodes) {
8375   jqNodes = jqLite(jqNodes);
8376   var i = jqNodes.length;
8377
8378   if (i <= 1) {
8379     return jqNodes;
8380   }
8381
8382   while (i--) {
8383     var node = jqNodes[i];
8384     if (node.nodeType === NODE_TYPE_COMMENT) {
8385       splice.call(jqNodes, i, 1);
8386     }
8387   }
8388   return jqNodes;
8389 }
8390
8391 var $controllerMinErr = minErr('$controller');
8392
8393 /**
8394  * @ngdoc provider
8395  * @name $controllerProvider
8396  * @description
8397  * The {@link ng.$controller $controller service} is used by Angular to create new
8398  * controllers.
8399  *
8400  * This provider allows controller registration via the
8401  * {@link ng.$controllerProvider#register register} method.
8402  */
8403 function $ControllerProvider() {
8404   var controllers = {},
8405       globals = false,
8406       CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
8407
8408
8409   /**
8410    * @ngdoc method
8411    * @name $controllerProvider#register
8412    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
8413    *    the names and the values are the constructors.
8414    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
8415    *    annotations in the array notation).
8416    */
8417   this.register = function(name, constructor) {
8418     assertNotHasOwnProperty(name, 'controller');
8419     if (isObject(name)) {
8420       extend(controllers, name);
8421     } else {
8422       controllers[name] = constructor;
8423     }
8424   };
8425
8426   /**
8427    * @ngdoc method
8428    * @name $controllerProvider#allowGlobals
8429    * @description If called, allows `$controller` to find controller constructors on `window`
8430    */
8431   this.allowGlobals = function() {
8432     globals = true;
8433   };
8434
8435
8436   this.$get = ['$injector', '$window', function($injector, $window) {
8437
8438     /**
8439      * @ngdoc service
8440      * @name $controller
8441      * @requires $injector
8442      *
8443      * @param {Function|string} constructor If called with a function then it's considered to be the
8444      *    controller constructor function. Otherwise it's considered to be a string which is used
8445      *    to retrieve the controller constructor using the following steps:
8446      *
8447      *    * check if a controller with given name is registered via `$controllerProvider`
8448      *    * check if evaluating the string on the current scope returns a constructor
8449      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
8450      *      `window` object (not recommended)
8451      *
8452      *    The string can use the `controller as property` syntax, where the controller instance is published
8453      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
8454      *    to work correctly.
8455      *
8456      * @param {Object} locals Injection locals for Controller.
8457      * @return {Object} Instance of given controller.
8458      *
8459      * @description
8460      * `$controller` service is responsible for instantiating controllers.
8461      *
8462      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
8463      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
8464      */
8465     return function(expression, locals, later, ident) {
8466       // PRIVATE API:
8467       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
8468       //                     If true, $controller will allocate the object with the correct
8469       //                     prototype chain, but will not invoke the controller until a returned
8470       //                     callback is invoked.
8471       //   param `ident` --- An optional label which overrides the label parsed from the controller
8472       //                     expression, if any.
8473       var instance, match, constructor, identifier;
8474       later = later === true;
8475       if (ident && isString(ident)) {
8476         identifier = ident;
8477       }
8478
8479       if (isString(expression)) {
8480         match = expression.match(CNTRL_REG);
8481         if (!match) {
8482           throw $controllerMinErr('ctrlfmt',
8483             "Badly formed controller string '{0}'. " +
8484             "Must match `__name__ as __id__` or `__name__`.", expression);
8485         }
8486         constructor = match[1],
8487         identifier = identifier || match[3];
8488         expression = controllers.hasOwnProperty(constructor)
8489             ? controllers[constructor]
8490             : getter(locals.$scope, constructor, true) ||
8491                 (globals ? getter($window, constructor, true) : undefined);
8492
8493         assertArgFn(expression, constructor, true);
8494       }
8495
8496       if (later) {
8497         // Instantiate controller later:
8498         // This machinery is used to create an instance of the object before calling the
8499         // controller's constructor itself.
8500         //
8501         // This allows properties to be added to the controller before the constructor is
8502         // invoked. Primarily, this is used for isolate scope bindings in $compile.
8503         //
8504         // This feature is not intended for use by applications, and is thus not documented
8505         // publicly.
8506         // Object creation: http://jsperf.com/create-constructor/2
8507         var controllerPrototype = (isArray(expression) ?
8508           expression[expression.length - 1] : expression).prototype;
8509         instance = Object.create(controllerPrototype || null);
8510
8511         if (identifier) {
8512           addIdentifier(locals, identifier, instance, constructor || expression.name);
8513         }
8514
8515         return extend(function() {
8516           $injector.invoke(expression, instance, locals, constructor);
8517           return instance;
8518         }, {
8519           instance: instance,
8520           identifier: identifier
8521         });
8522       }
8523
8524       instance = $injector.instantiate(expression, locals, constructor);
8525
8526       if (identifier) {
8527         addIdentifier(locals, identifier, instance, constructor || expression.name);
8528       }
8529
8530       return instance;
8531     };
8532
8533     function addIdentifier(locals, identifier, instance, name) {
8534       if (!(locals && isObject(locals.$scope))) {
8535         throw minErr('$controller')('noscp',
8536           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
8537           name, identifier);
8538       }
8539
8540       locals.$scope[identifier] = instance;
8541     }
8542   }];
8543 }
8544
8545 /**
8546  * @ngdoc service
8547  * @name $document
8548  * @requires $window
8549  *
8550  * @description
8551  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
8552  *
8553  * @example
8554    <example module="documentExample">
8555      <file name="index.html">
8556        <div ng-controller="ExampleController">
8557          <p>$document title: <b ng-bind="title"></b></p>
8558          <p>window.document title: <b ng-bind="windowTitle"></b></p>
8559        </div>
8560      </file>
8561      <file name="script.js">
8562        angular.module('documentExample', [])
8563          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
8564            $scope.title = $document[0].title;
8565            $scope.windowTitle = angular.element(window.document)[0].title;
8566          }]);
8567      </file>
8568    </example>
8569  */
8570 function $DocumentProvider() {
8571   this.$get = ['$window', function(window) {
8572     return jqLite(window.document);
8573   }];
8574 }
8575
8576 /**
8577  * @ngdoc service
8578  * @name $exceptionHandler
8579  * @requires ng.$log
8580  *
8581  * @description
8582  * Any uncaught exception in angular expressions is delegated to this service.
8583  * The default implementation simply delegates to `$log.error` which logs it into
8584  * the browser console.
8585  *
8586  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
8587  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
8588  *
8589  * ## Example:
8590  *
8591  * ```js
8592  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
8593  *     return function(exception, cause) {
8594  *       exception.message += ' (caused by "' + cause + '")';
8595  *       throw exception;
8596  *     };
8597  *   });
8598  * ```
8599  *
8600  * This example will override the normal action of `$exceptionHandler`, to make angular
8601  * exceptions fail hard when they happen, instead of just logging to the console.
8602  *
8603  * <hr />
8604  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
8605  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
8606  * (unless executed during a digest).
8607  *
8608  * If you wish, you can manually delegate exceptions, e.g.
8609  * `try { ... } catch(e) { $exceptionHandler(e); }`
8610  *
8611  * @param {Error} exception Exception associated with the error.
8612  * @param {string=} cause optional information about the context in which
8613  *       the error was thrown.
8614  *
8615  */
8616 function $ExceptionHandlerProvider() {
8617   this.$get = ['$log', function($log) {
8618     return function(exception, cause) {
8619       $log.error.apply($log, arguments);
8620     };
8621   }];
8622 }
8623
8624 var APPLICATION_JSON = 'application/json';
8625 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
8626 var JSON_START = /^\[|^\{(?!\{)/;
8627 var JSON_ENDS = {
8628   '[': /]$/,
8629   '{': /}$/
8630 };
8631 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
8632
8633 function defaultHttpResponseTransform(data, headers) {
8634   if (isString(data)) {
8635     // Strip json vulnerability protection prefix and trim whitespace
8636     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
8637
8638     if (tempData) {
8639       var contentType = headers('Content-Type');
8640       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
8641         data = fromJson(tempData);
8642       }
8643     }
8644   }
8645
8646   return data;
8647 }
8648
8649 function isJsonLike(str) {
8650     var jsonStart = str.match(JSON_START);
8651     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
8652 }
8653
8654 /**
8655  * Parse headers into key value object
8656  *
8657  * @param {string} headers Raw headers as a string
8658  * @returns {Object} Parsed headers as key value object
8659  */
8660 function parseHeaders(headers) {
8661   var parsed = createMap(), key, val, i;
8662
8663   if (!headers) return parsed;
8664
8665   forEach(headers.split('\n'), function(line) {
8666     i = line.indexOf(':');
8667     key = lowercase(trim(line.substr(0, i)));
8668     val = trim(line.substr(i + 1));
8669
8670     if (key) {
8671       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
8672     }
8673   });
8674
8675   return parsed;
8676 }
8677
8678
8679 /**
8680  * Returns a function that provides access to parsed headers.
8681  *
8682  * Headers are lazy parsed when first requested.
8683  * @see parseHeaders
8684  *
8685  * @param {(string|Object)} headers Headers to provide access to.
8686  * @returns {function(string=)} Returns a getter function which if called with:
8687  *
8688  *   - if called with single an argument returns a single header value or null
8689  *   - if called with no arguments returns an object containing all headers.
8690  */
8691 function headersGetter(headers) {
8692   var headersObj = isObject(headers) ? headers : undefined;
8693
8694   return function(name) {
8695     if (!headersObj) headersObj =  parseHeaders(headers);
8696
8697     if (name) {
8698       var value = headersObj[lowercase(name)];
8699       if (value === void 0) {
8700         value = null;
8701       }
8702       return value;
8703     }
8704
8705     return headersObj;
8706   };
8707 }
8708
8709
8710 /**
8711  * Chain all given functions
8712  *
8713  * This function is used for both request and response transforming
8714  *
8715  * @param {*} data Data to transform.
8716  * @param {function(string=)} headers HTTP headers getter fn.
8717  * @param {number} status HTTP status code of the response.
8718  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
8719  * @returns {*} Transformed data.
8720  */
8721 function transformData(data, headers, status, fns) {
8722   if (isFunction(fns))
8723     return fns(data, headers, status);
8724
8725   forEach(fns, function(fn) {
8726     data = fn(data, headers, status);
8727   });
8728
8729   return data;
8730 }
8731
8732
8733 function isSuccess(status) {
8734   return 200 <= status && status < 300;
8735 }
8736
8737
8738 /**
8739  * @ngdoc provider
8740  * @name $httpProvider
8741  * @description
8742  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
8743  * */
8744 function $HttpProvider() {
8745   /**
8746    * @ngdoc property
8747    * @name $httpProvider#defaults
8748    * @description
8749    *
8750    * Object containing default values for all {@link ng.$http $http} requests.
8751    *
8752    * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
8753    * that will provide the cache for all requests who set their `cache` property to `true`.
8754    * If you set the `default.cache = false` then only requests that specify their own custom
8755    * cache object will be cached. See {@link $http#caching $http Caching} for more information.
8756    *
8757    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
8758    * Defaults value is `'XSRF-TOKEN'`.
8759    *
8760    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
8761    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
8762    *
8763    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
8764    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
8765    * setting default headers.
8766    *     - **`defaults.headers.common`**
8767    *     - **`defaults.headers.post`**
8768    *     - **`defaults.headers.put`**
8769    *     - **`defaults.headers.patch`**
8770    *
8771    **/
8772   var defaults = this.defaults = {
8773     // transform incoming response data
8774     transformResponse: [defaultHttpResponseTransform],
8775
8776     // transform outgoing request data
8777     transformRequest: [function(d) {
8778       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
8779     }],
8780
8781     // default headers
8782     headers: {
8783       common: {
8784         'Accept': 'application/json, text/plain, */*'
8785       },
8786       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8787       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8788       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
8789     },
8790
8791     xsrfCookieName: 'XSRF-TOKEN',
8792     xsrfHeaderName: 'X-XSRF-TOKEN'
8793   };
8794
8795   var useApplyAsync = false;
8796   /**
8797    * @ngdoc method
8798    * @name $httpProvider#useApplyAsync
8799    * @description
8800    *
8801    * Configure $http service to combine processing of multiple http responses received at around
8802    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
8803    * significant performance improvement for bigger applications that make many HTTP requests
8804    * concurrently (common during application bootstrap).
8805    *
8806    * Defaults to false. If no value is specifed, returns the current configured value.
8807    *
8808    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
8809    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
8810    *    to load and share the same digest cycle.
8811    *
8812    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
8813    *    otherwise, returns the current configured value.
8814    **/
8815   this.useApplyAsync = function(value) {
8816     if (isDefined(value)) {
8817       useApplyAsync = !!value;
8818       return this;
8819     }
8820     return useApplyAsync;
8821   };
8822
8823   /**
8824    * @ngdoc property
8825    * @name $httpProvider#interceptors
8826    * @description
8827    *
8828    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
8829    * pre-processing of request or postprocessing of responses.
8830    *
8831    * These service factories are ordered by request, i.e. they are applied in the same order as the
8832    * array, on request, but reverse order, on response.
8833    *
8834    * {@link ng.$http#interceptors Interceptors detailed info}
8835    **/
8836   var interceptorFactories = this.interceptors = [];
8837
8838   this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
8839       function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
8840
8841     var defaultCache = $cacheFactory('$http');
8842
8843     /**
8844      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
8845      * The reversal is needed so that we can build up the interception chain around the
8846      * server request.
8847      */
8848     var reversedInterceptors = [];
8849
8850     forEach(interceptorFactories, function(interceptorFactory) {
8851       reversedInterceptors.unshift(isString(interceptorFactory)
8852           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
8853     });
8854
8855     /**
8856      * @ngdoc service
8857      * @kind function
8858      * @name $http
8859      * @requires ng.$httpBackend
8860      * @requires $cacheFactory
8861      * @requires $rootScope
8862      * @requires $q
8863      * @requires $injector
8864      *
8865      * @description
8866      * The `$http` service is a core Angular service that facilitates communication with the remote
8867      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
8868      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
8869      *
8870      * For unit testing applications that use `$http` service, see
8871      * {@link ngMock.$httpBackend $httpBackend mock}.
8872      *
8873      * For a higher level of abstraction, please check out the {@link ngResource.$resource
8874      * $resource} service.
8875      *
8876      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
8877      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
8878      * it is important to familiarize yourself with these APIs and the guarantees they provide.
8879      *
8880      *
8881      * ## General usage
8882      * The `$http` service is a function which takes a single argument — a configuration object —
8883      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
8884      * with two $http specific methods: `success` and `error`.
8885      *
8886      * ```js
8887      *   // Simple GET request example :
8888      *   $http.get('/someUrl').
8889      *     success(function(data, status, headers, config) {
8890      *       // this callback will be called asynchronously
8891      *       // when the response is available
8892      *     }).
8893      *     error(function(data, status, headers, config) {
8894      *       // called asynchronously if an error occurs
8895      *       // or server returns response with an error status.
8896      *     });
8897      * ```
8898      *
8899      * ```js
8900      *   // Simple POST request example (passing data) :
8901      *   $http.post('/someUrl', {msg:'hello word!'}).
8902      *     success(function(data, status, headers, config) {
8903      *       // this callback will be called asynchronously
8904      *       // when the response is available
8905      *     }).
8906      *     error(function(data, status, headers, config) {
8907      *       // called asynchronously if an error occurs
8908      *       // or server returns response with an error status.
8909      *     });
8910      * ```
8911      *
8912      *
8913      * Since the returned value of calling the $http function is a `promise`, you can also use
8914      * the `then` method to register callbacks, and these callbacks will receive a single argument –
8915      * an object representing the response. See the API signature and type info below for more
8916      * details.
8917      *
8918      * A response status code between 200 and 299 is considered a success status and
8919      * will result in the success callback being called. Note that if the response is a redirect,
8920      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
8921      * called for such responses.
8922      *
8923      * ## Writing Unit Tests that use $http
8924      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
8925      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
8926      * request using trained responses.
8927      *
8928      * ```
8929      * $httpBackend.expectGET(...);
8930      * $http.get(...);
8931      * $httpBackend.flush();
8932      * ```
8933      *
8934      * ## Shortcut methods
8935      *
8936      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
8937      * request data must be passed in for POST/PUT requests.
8938      *
8939      * ```js
8940      *   $http.get('/someUrl').success(successCallback);
8941      *   $http.post('/someUrl', data).success(successCallback);
8942      * ```
8943      *
8944      * Complete list of shortcut methods:
8945      *
8946      * - {@link ng.$http#get $http.get}
8947      * - {@link ng.$http#head $http.head}
8948      * - {@link ng.$http#post $http.post}
8949      * - {@link ng.$http#put $http.put}
8950      * - {@link ng.$http#delete $http.delete}
8951      * - {@link ng.$http#jsonp $http.jsonp}
8952      * - {@link ng.$http#patch $http.patch}
8953      *
8954      *
8955      * ## Setting HTTP Headers
8956      *
8957      * The $http service will automatically add certain HTTP headers to all requests. These defaults
8958      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
8959      * object, which currently contains this default configuration:
8960      *
8961      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
8962      *   - `Accept: application/json, text/plain, * / *`
8963      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
8964      *   - `Content-Type: application/json`
8965      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
8966      *   - `Content-Type: application/json`
8967      *
8968      * To add or overwrite these defaults, simply add or remove a property from these configuration
8969      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
8970      * with the lowercased HTTP method name as the key, e.g.
8971      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
8972      *
8973      * The defaults can also be set at runtime via the `$http.defaults` object in the same
8974      * fashion. For example:
8975      *
8976      * ```
8977      * module.run(function($http) {
8978      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
8979      * });
8980      * ```
8981      *
8982      * In addition, you can supply a `headers` property in the config object passed when
8983      * calling `$http(config)`, which overrides the defaults without changing them globally.
8984      *
8985      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
8986      * Use the `headers` property, setting the desired header to `undefined`. For example:
8987      *
8988      * ```js
8989      * var req = {
8990      *  method: 'POST',
8991      *  url: 'http://example.com',
8992      *  headers: {
8993      *    'Content-Type': undefined
8994      *  },
8995      *  data: { test: 'test' }
8996      * }
8997      *
8998      * $http(req).success(function(){...}).error(function(){...});
8999      * ```
9000      *
9001      * ## Transforming Requests and Responses
9002      *
9003      * Both requests and responses can be transformed using transformation functions: `transformRequest`
9004      * and `transformResponse`. These properties can be a single function that returns
9005      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9006      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9007      *
9008      * ### Default Transformations
9009      *
9010      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9011      * `defaults.transformResponse` properties. If a request does not provide its own transformations
9012      * then these will be applied.
9013      *
9014      * You can augment or replace the default transformations by modifying these properties by adding to or
9015      * replacing the array.
9016      *
9017      * Angular provides the following default transformations:
9018      *
9019      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9020      *
9021      * - If the `data` property of the request configuration object contains an object, serialize it
9022      *   into JSON format.
9023      *
9024      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9025      *
9026      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9027      *  - If JSON response is detected, deserialize it using a JSON parser.
9028      *
9029      *
9030      * ### Overriding the Default Transformations Per Request
9031      *
9032      * If you wish override the request/response transformations only for a single request then provide
9033      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9034      * into `$http`.
9035      *
9036      * Note that if you provide these properties on the config object the default transformations will be
9037      * overwritten. If you wish to augment the default transformations then you must include them in your
9038      * local transformation array.
9039      *
9040      * The following code demonstrates adding a new response transformation to be run after the default response
9041      * transformations have been run.
9042      *
9043      * ```js
9044      * function appendTransform(defaults, transform) {
9045      *
9046      *   // We can't guarantee that the default transformation is an array
9047      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9048      *
9049      *   // Append the new transformation to the defaults
9050      *   return defaults.concat(transform);
9051      * }
9052      *
9053      * $http({
9054      *   url: '...',
9055      *   method: 'GET',
9056      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9057      *     return doTransform(value);
9058      *   })
9059      * });
9060      * ```
9061      *
9062      *
9063      * ## Caching
9064      *
9065      * To enable caching, set the request configuration `cache` property to `true` (to use default
9066      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
9067      * When the cache is enabled, `$http` stores the response from the server in the specified
9068      * cache. The next time the same request is made, the response is served from the cache without
9069      * sending a request to the server.
9070      *
9071      * Note that even if the response is served from cache, delivery of the data is asynchronous in
9072      * the same way that real requests are.
9073      *
9074      * If there are multiple GET requests for the same URL that should be cached using the same
9075      * cache, but the cache is not populated yet, only one request to the server will be made and
9076      * the remaining requests will be fulfilled using the response from the first request.
9077      *
9078      * You can change the default cache to a new object (built with
9079      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
9080      * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
9081      * their `cache` property to `true` will now use this cache object.
9082      *
9083      * If you set the default cache to `false` then only requests that specify their own custom
9084      * cache object will be cached.
9085      *
9086      * ## Interceptors
9087      *
9088      * Before you start creating interceptors, be sure to understand the
9089      * {@link ng.$q $q and deferred/promise APIs}.
9090      *
9091      * For purposes of global error handling, authentication, or any kind of synchronous or
9092      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
9093      * able to intercept requests before they are handed to the server and
9094      * responses before they are handed over to the application code that
9095      * initiated these requests. The interceptors leverage the {@link ng.$q
9096      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
9097      *
9098      * The interceptors are service factories that are registered with the `$httpProvider` by
9099      * adding them to the `$httpProvider.interceptors` array. The factory is called and
9100      * injected with dependencies (if specified) and returns the interceptor.
9101      *
9102      * There are two kinds of interceptors (and two kinds of rejection interceptors):
9103      *
9104      *   * `request`: interceptors get called with a http `config` object. The function is free to
9105      *     modify the `config` object or create a new one. The function needs to return the `config`
9106      *     object directly, or a promise containing the `config` or a new `config` object.
9107      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
9108      *     resolved with a rejection.
9109      *   * `response`: interceptors get called with http `response` object. The function is free to
9110      *     modify the `response` object or create a new one. The function needs to return the `response`
9111      *     object directly, or as a promise containing the `response` or a new `response` object.
9112      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
9113      *     resolved with a rejection.
9114      *
9115      *
9116      * ```js
9117      *   // register the interceptor as a service
9118      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
9119      *     return {
9120      *       // optional method
9121      *       'request': function(config) {
9122      *         // do something on success
9123      *         return config;
9124      *       },
9125      *
9126      *       // optional method
9127      *      'requestError': function(rejection) {
9128      *         // do something on error
9129      *         if (canRecover(rejection)) {
9130      *           return responseOrNewPromise
9131      *         }
9132      *         return $q.reject(rejection);
9133      *       },
9134      *
9135      *
9136      *
9137      *       // optional method
9138      *       'response': function(response) {
9139      *         // do something on success
9140      *         return response;
9141      *       },
9142      *
9143      *       // optional method
9144      *      'responseError': function(rejection) {
9145      *         // do something on error
9146      *         if (canRecover(rejection)) {
9147      *           return responseOrNewPromise
9148      *         }
9149      *         return $q.reject(rejection);
9150      *       }
9151      *     };
9152      *   });
9153      *
9154      *   $httpProvider.interceptors.push('myHttpInterceptor');
9155      *
9156      *
9157      *   // alternatively, register the interceptor via an anonymous factory
9158      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
9159      *     return {
9160      *      'request': function(config) {
9161      *          // same as above
9162      *       },
9163      *
9164      *       'response': function(response) {
9165      *          // same as above
9166      *       }
9167      *     };
9168      *   });
9169      * ```
9170      *
9171      * ## Security Considerations
9172      *
9173      * When designing web applications, consider security threats from:
9174      *
9175      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9176      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
9177      *
9178      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
9179      * pre-configured with strategies that address these issues, but for this to work backend server
9180      * cooperation is required.
9181      *
9182      * ### JSON Vulnerability Protection
9183      *
9184      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9185      * allows third party website to turn your JSON resource URL into
9186      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
9187      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
9188      * Angular will automatically strip the prefix before processing it as JSON.
9189      *
9190      * For example if your server needs to return:
9191      * ```js
9192      * ['one','two']
9193      * ```
9194      *
9195      * which is vulnerable to attack, your server can return:
9196      * ```js
9197      * )]}',
9198      * ['one','two']
9199      * ```
9200      *
9201      * Angular will strip the prefix, before processing the JSON.
9202      *
9203      *
9204      * ### Cross Site Request Forgery (XSRF) Protection
9205      *
9206      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
9207      * an unauthorized site can gain your user's private data. Angular provides a mechanism
9208      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
9209      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
9210      * JavaScript that runs on your domain could read the cookie, your server can be assured that
9211      * the XHR came from JavaScript running on your domain. The header will not be set for
9212      * cross-domain requests.
9213      *
9214      * To take advantage of this, your server needs to set a token in a JavaScript readable session
9215      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
9216      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
9217      * that only JavaScript running on your domain could have sent the request. The token must be
9218      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
9219      * making up its own tokens). We recommend that the token is a digest of your site's
9220      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
9221      * for added security.
9222      *
9223      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
9224      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
9225      * or the per-request config object.
9226      *
9227      *
9228      * @param {object} config Object describing the request to be made and how it should be
9229      *    processed. The object has following properties:
9230      *
9231      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
9232      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
9233      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
9234      *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
9235      *      JSONified.
9236      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
9237      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
9238      *      HTTP headers to send to the server. If the return value of a function is null, the
9239      *      header will not be sent.
9240      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
9241      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
9242      *    - **transformRequest** –
9243      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
9244      *      transform function or an array of such functions. The transform function takes the http
9245      *      request body and headers and returns its transformed (typically serialized) version.
9246      *      See {@link ng.$http#overriding-the-default-transformations-per-request
9247      *      Overriding the Default Transformations}
9248      *    - **transformResponse** –
9249      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
9250      *      transform function or an array of such functions. The transform function takes the http
9251      *      response body, headers and status and returns its transformed (typically deserialized) version.
9252      *      See {@link ng.$http#overriding-the-default-transformations-per-request
9253      *      Overriding the Default Transformations}
9254      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
9255      *      GET request, otherwise if a cache instance built with
9256      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
9257      *      caching.
9258      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
9259      *      that should abort the request when resolved.
9260      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
9261      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
9262      *      for more information.
9263      *    - **responseType** - `{string}` - see
9264      *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
9265      *
9266      * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
9267      *   standard `then` method and two http specific methods: `success` and `error`. The `then`
9268      *   method takes two arguments a success and an error callback which will be called with a
9269      *   response object. The `success` and `error` methods take a single argument - a function that
9270      *   will be called when the request succeeds or fails respectively. The arguments passed into
9271      *   these functions are destructured representation of the response object passed into the
9272      *   `then` method. The response object has these properties:
9273      *
9274      *   - **data** – `{string|Object}` – The response body transformed with the transform
9275      *     functions.
9276      *   - **status** – `{number}` – HTTP status code of the response.
9277      *   - **headers** – `{function([headerName])}` – Header getter function.
9278      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9279      *   - **statusText** – `{string}` – HTTP status text of the response.
9280      *
9281      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
9282      *   requests. This is primarily meant to be used for debugging purposes.
9283      *
9284      *
9285      * @example
9286 <example module="httpExample">
9287 <file name="index.html">
9288   <div ng-controller="FetchController">
9289     <select ng-model="method">
9290       <option>GET</option>
9291       <option>JSONP</option>
9292     </select>
9293     <input type="text" ng-model="url" size="80"/>
9294     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
9295     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
9296     <button id="samplejsonpbtn"
9297       ng-click="updateModel('JSONP',
9298                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
9299       Sample JSONP
9300     </button>
9301     <button id="invalidjsonpbtn"
9302       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
9303         Invalid JSONP
9304       </button>
9305     <pre>http status code: {{status}}</pre>
9306     <pre>http response data: {{data}}</pre>
9307   </div>
9308 </file>
9309 <file name="script.js">
9310   angular.module('httpExample', [])
9311     .controller('FetchController', ['$scope', '$http', '$templateCache',
9312       function($scope, $http, $templateCache) {
9313         $scope.method = 'GET';
9314         $scope.url = 'http-hello.html';
9315
9316         $scope.fetch = function() {
9317           $scope.code = null;
9318           $scope.response = null;
9319
9320           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
9321             success(function(data, status) {
9322               $scope.status = status;
9323               $scope.data = data;
9324             }).
9325             error(function(data, status) {
9326               $scope.data = data || "Request failed";
9327               $scope.status = status;
9328           });
9329         };
9330
9331         $scope.updateModel = function(method, url) {
9332           $scope.method = method;
9333           $scope.url = url;
9334         };
9335       }]);
9336 </file>
9337 <file name="http-hello.html">
9338   Hello, $http!
9339 </file>
9340 <file name="protractor.js" type="protractor">
9341   var status = element(by.binding('status'));
9342   var data = element(by.binding('data'));
9343   var fetchBtn = element(by.id('fetchbtn'));
9344   var sampleGetBtn = element(by.id('samplegetbtn'));
9345   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
9346   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
9347
9348   it('should make an xhr GET request', function() {
9349     sampleGetBtn.click();
9350     fetchBtn.click();
9351     expect(status.getText()).toMatch('200');
9352     expect(data.getText()).toMatch(/Hello, \$http!/);
9353   });
9354
9355 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
9356 // it('should make a JSONP request to angularjs.org', function() {
9357 //   sampleJsonpBtn.click();
9358 //   fetchBtn.click();
9359 //   expect(status.getText()).toMatch('200');
9360 //   expect(data.getText()).toMatch(/Super Hero!/);
9361 // });
9362
9363   it('should make JSONP request to invalid URL and invoke the error handler',
9364       function() {
9365     invalidJsonpBtn.click();
9366     fetchBtn.click();
9367     expect(status.getText()).toMatch('0');
9368     expect(data.getText()).toMatch('Request failed');
9369   });
9370 </file>
9371 </example>
9372      */
9373     function $http(requestConfig) {
9374
9375       if (!angular.isObject(requestConfig)) {
9376         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
9377       }
9378
9379       var config = extend({
9380         method: 'get',
9381         transformRequest: defaults.transformRequest,
9382         transformResponse: defaults.transformResponse
9383       }, requestConfig);
9384
9385       config.headers = mergeHeaders(requestConfig);
9386       config.method = uppercase(config.method);
9387
9388       var serverRequest = function(config) {
9389         var headers = config.headers;
9390         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
9391
9392         // strip content-type if data is undefined
9393         if (isUndefined(reqData)) {
9394           forEach(headers, function(value, header) {
9395             if (lowercase(header) === 'content-type') {
9396                 delete headers[header];
9397             }
9398           });
9399         }
9400
9401         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
9402           config.withCredentials = defaults.withCredentials;
9403         }
9404
9405         // send request
9406         return sendReq(config, reqData).then(transformResponse, transformResponse);
9407       };
9408
9409       var chain = [serverRequest, undefined];
9410       var promise = $q.when(config);
9411
9412       // apply interceptors
9413       forEach(reversedInterceptors, function(interceptor) {
9414         if (interceptor.request || interceptor.requestError) {
9415           chain.unshift(interceptor.request, interceptor.requestError);
9416         }
9417         if (interceptor.response || interceptor.responseError) {
9418           chain.push(interceptor.response, interceptor.responseError);
9419         }
9420       });
9421
9422       while (chain.length) {
9423         var thenFn = chain.shift();
9424         var rejectFn = chain.shift();
9425
9426         promise = promise.then(thenFn, rejectFn);
9427       }
9428
9429       promise.success = function(fn) {
9430         assertArgFn(fn, 'fn');
9431
9432         promise.then(function(response) {
9433           fn(response.data, response.status, response.headers, config);
9434         });
9435         return promise;
9436       };
9437
9438       promise.error = function(fn) {
9439         assertArgFn(fn, 'fn');
9440
9441         promise.then(null, function(response) {
9442           fn(response.data, response.status, response.headers, config);
9443         });
9444         return promise;
9445       };
9446
9447       return promise;
9448
9449       function transformResponse(response) {
9450         // make a copy since the response must be cacheable
9451         var resp = extend({}, response);
9452         if (!response.data) {
9453           resp.data = response.data;
9454         } else {
9455           resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
9456         }
9457         return (isSuccess(response.status))
9458           ? resp
9459           : $q.reject(resp);
9460       }
9461
9462       function executeHeaderFns(headers) {
9463         var headerContent, processedHeaders = {};
9464
9465         forEach(headers, function(headerFn, header) {
9466           if (isFunction(headerFn)) {
9467             headerContent = headerFn();
9468             if (headerContent != null) {
9469               processedHeaders[header] = headerContent;
9470             }
9471           } else {
9472             processedHeaders[header] = headerFn;
9473           }
9474         });
9475
9476         return processedHeaders;
9477       }
9478
9479       function mergeHeaders(config) {
9480         var defHeaders = defaults.headers,
9481             reqHeaders = extend({}, config.headers),
9482             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
9483
9484         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
9485
9486         // using for-in instead of forEach to avoid unecessary iteration after header has been found
9487         defaultHeadersIteration:
9488         for (defHeaderName in defHeaders) {
9489           lowercaseDefHeaderName = lowercase(defHeaderName);
9490
9491           for (reqHeaderName in reqHeaders) {
9492             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
9493               continue defaultHeadersIteration;
9494             }
9495           }
9496
9497           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
9498         }
9499
9500         // execute if header value is a function for merged headers
9501         return executeHeaderFns(reqHeaders);
9502       }
9503     }
9504
9505     $http.pendingRequests = [];
9506
9507     /**
9508      * @ngdoc method
9509      * @name $http#get
9510      *
9511      * @description
9512      * Shortcut method to perform `GET` request.
9513      *
9514      * @param {string} url Relative or absolute URL specifying the destination of the request
9515      * @param {Object=} config Optional configuration object
9516      * @returns {HttpPromise} Future object
9517      */
9518
9519     /**
9520      * @ngdoc method
9521      * @name $http#delete
9522      *
9523      * @description
9524      * Shortcut method to perform `DELETE` request.
9525      *
9526      * @param {string} url Relative or absolute URL specifying the destination of the request
9527      * @param {Object=} config Optional configuration object
9528      * @returns {HttpPromise} Future object
9529      */
9530
9531     /**
9532      * @ngdoc method
9533      * @name $http#head
9534      *
9535      * @description
9536      * Shortcut method to perform `HEAD` request.
9537      *
9538      * @param {string} url Relative or absolute URL specifying the destination of the request
9539      * @param {Object=} config Optional configuration object
9540      * @returns {HttpPromise} Future object
9541      */
9542
9543     /**
9544      * @ngdoc method
9545      * @name $http#jsonp
9546      *
9547      * @description
9548      * Shortcut method to perform `JSONP` request.
9549      *
9550      * @param {string} url Relative or absolute URL specifying the destination of the request.
9551      *                     The name of the callback should be the string `JSON_CALLBACK`.
9552      * @param {Object=} config Optional configuration object
9553      * @returns {HttpPromise} Future object
9554      */
9555     createShortMethods('get', 'delete', 'head', 'jsonp');
9556
9557     /**
9558      * @ngdoc method
9559      * @name $http#post
9560      *
9561      * @description
9562      * Shortcut method to perform `POST` request.
9563      *
9564      * @param {string} url Relative or absolute URL specifying the destination of the request
9565      * @param {*} data Request content
9566      * @param {Object=} config Optional configuration object
9567      * @returns {HttpPromise} Future object
9568      */
9569
9570     /**
9571      * @ngdoc method
9572      * @name $http#put
9573      *
9574      * @description
9575      * Shortcut method to perform `PUT` request.
9576      *
9577      * @param {string} url Relative or absolute URL specifying the destination of the request
9578      * @param {*} data Request content
9579      * @param {Object=} config Optional configuration object
9580      * @returns {HttpPromise} Future object
9581      */
9582
9583      /**
9584       * @ngdoc method
9585       * @name $http#patch
9586       *
9587       * @description
9588       * Shortcut method to perform `PATCH` request.
9589       *
9590       * @param {string} url Relative or absolute URL specifying the destination of the request
9591       * @param {*} data Request content
9592       * @param {Object=} config Optional configuration object
9593       * @returns {HttpPromise} Future object
9594       */
9595     createShortMethodsWithData('post', 'put', 'patch');
9596
9597         /**
9598          * @ngdoc property
9599          * @name $http#defaults
9600          *
9601          * @description
9602          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
9603          * default headers, withCredentials as well as request and response transformations.
9604          *
9605          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
9606          */
9607     $http.defaults = defaults;
9608
9609
9610     return $http;
9611
9612
9613     function createShortMethods(names) {
9614       forEach(arguments, function(name) {
9615         $http[name] = function(url, config) {
9616           return $http(extend(config || {}, {
9617             method: name,
9618             url: url
9619           }));
9620         };
9621       });
9622     }
9623
9624
9625     function createShortMethodsWithData(name) {
9626       forEach(arguments, function(name) {
9627         $http[name] = function(url, data, config) {
9628           return $http(extend(config || {}, {
9629             method: name,
9630             url: url,
9631             data: data
9632           }));
9633         };
9634       });
9635     }
9636
9637
9638     /**
9639      * Makes the request.
9640      *
9641      * !!! ACCESSES CLOSURE VARS:
9642      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
9643      */
9644     function sendReq(config, reqData) {
9645       var deferred = $q.defer(),
9646           promise = deferred.promise,
9647           cache,
9648           cachedResp,
9649           reqHeaders = config.headers,
9650           url = buildUrl(config.url, config.params);
9651
9652       $http.pendingRequests.push(config);
9653       promise.then(removePendingReq, removePendingReq);
9654
9655
9656       if ((config.cache || defaults.cache) && config.cache !== false &&
9657           (config.method === 'GET' || config.method === 'JSONP')) {
9658         cache = isObject(config.cache) ? config.cache
9659               : isObject(defaults.cache) ? defaults.cache
9660               : defaultCache;
9661       }
9662
9663       if (cache) {
9664         cachedResp = cache.get(url);
9665         if (isDefined(cachedResp)) {
9666           if (isPromiseLike(cachedResp)) {
9667             // cached request has already been sent, but there is no response yet
9668             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
9669           } else {
9670             // serving from cache
9671             if (isArray(cachedResp)) {
9672               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
9673             } else {
9674               resolvePromise(cachedResp, 200, {}, 'OK');
9675             }
9676           }
9677         } else {
9678           // put the promise for the non-transformed response into cache as a placeholder
9679           cache.put(url, promise);
9680         }
9681       }
9682
9683
9684       // if we won't have the response in cache, set the xsrf headers and
9685       // send the request to the backend
9686       if (isUndefined(cachedResp)) {
9687         var xsrfValue = urlIsSameOrigin(config.url)
9688             ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
9689             : undefined;
9690         if (xsrfValue) {
9691           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
9692         }
9693
9694         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
9695             config.withCredentials, config.responseType);
9696       }
9697
9698       return promise;
9699
9700
9701       /**
9702        * Callback registered to $httpBackend():
9703        *  - caches the response if desired
9704        *  - resolves the raw $http promise
9705        *  - calls $apply
9706        */
9707       function done(status, response, headersString, statusText) {
9708         if (cache) {
9709           if (isSuccess(status)) {
9710             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
9711           } else {
9712             // remove promise from the cache
9713             cache.remove(url);
9714           }
9715         }
9716
9717         function resolveHttpPromise() {
9718           resolvePromise(response, status, headersString, statusText);
9719         }
9720
9721         if (useApplyAsync) {
9722           $rootScope.$applyAsync(resolveHttpPromise);
9723         } else {
9724           resolveHttpPromise();
9725           if (!$rootScope.$$phase) $rootScope.$apply();
9726         }
9727       }
9728
9729
9730       /**
9731        * Resolves the raw $http promise.
9732        */
9733       function resolvePromise(response, status, headers, statusText) {
9734         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
9735         status = status >= -1 ? status : 0;
9736
9737         (isSuccess(status) ? deferred.resolve : deferred.reject)({
9738           data: response,
9739           status: status,
9740           headers: headersGetter(headers),
9741           config: config,
9742           statusText: statusText
9743         });
9744       }
9745
9746       function resolvePromiseWithResult(result) {
9747         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
9748       }
9749
9750       function removePendingReq() {
9751         var idx = $http.pendingRequests.indexOf(config);
9752         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
9753       }
9754     }
9755
9756
9757     function buildUrl(url, params) {
9758       if (!params) return url;
9759       var parts = [];
9760       forEachSorted(params, function(value, key) {
9761         if (value === null || isUndefined(value)) return;
9762         if (!isArray(value)) value = [value];
9763
9764         forEach(value, function(v) {
9765           if (isObject(v)) {
9766             if (isDate(v)) {
9767               v = v.toISOString();
9768             } else {
9769               v = toJson(v);
9770             }
9771           }
9772           parts.push(encodeUriQuery(key) + '=' +
9773                      encodeUriQuery(v));
9774         });
9775       });
9776       if (parts.length > 0) {
9777         url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
9778       }
9779       return url;
9780     }
9781   }];
9782 }
9783
9784 function createXhr() {
9785     return new window.XMLHttpRequest();
9786 }
9787
9788 /**
9789  * @ngdoc service
9790  * @name $httpBackend
9791  * @requires $window
9792  * @requires $document
9793  *
9794  * @description
9795  * HTTP backend used by the {@link ng.$http service} that delegates to
9796  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
9797  *
9798  * You should never need to use this service directly, instead use the higher-level abstractions:
9799  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
9800  *
9801  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
9802  * $httpBackend} which can be trained with responses.
9803  */
9804 function $HttpBackendProvider() {
9805   this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
9806     return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
9807   }];
9808 }
9809
9810 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
9811   // TODO(vojta): fix the signature
9812   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
9813     $browser.$$incOutstandingRequestCount();
9814     url = url || $browser.url();
9815
9816     if (lowercase(method) == 'jsonp') {
9817       var callbackId = '_' + (callbacks.counter++).toString(36);
9818       callbacks[callbackId] = function(data) {
9819         callbacks[callbackId].data = data;
9820         callbacks[callbackId].called = true;
9821       };
9822
9823       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
9824           callbackId, function(status, text) {
9825         completeRequest(callback, status, callbacks[callbackId].data, "", text);
9826         callbacks[callbackId] = noop;
9827       });
9828     } else {
9829
9830       var xhr = createXhr();
9831
9832       xhr.open(method, url, true);
9833       forEach(headers, function(value, key) {
9834         if (isDefined(value)) {
9835             xhr.setRequestHeader(key, value);
9836         }
9837       });
9838
9839       xhr.onload = function requestLoaded() {
9840         var statusText = xhr.statusText || '';
9841
9842         // responseText is the old-school way of retrieving response (supported by IE9)
9843         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
9844         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
9845
9846         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
9847         var status = xhr.status === 1223 ? 204 : xhr.status;
9848
9849         // fix status code when it is 0 (0 status is undocumented).
9850         // Occurs when accessing file resources or on Android 4.1 stock browser
9851         // while retrieving files from application cache.
9852         if (status === 0) {
9853           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
9854         }
9855
9856         completeRequest(callback,
9857             status,
9858             response,
9859             xhr.getAllResponseHeaders(),
9860             statusText);
9861       };
9862
9863       var requestError = function() {
9864         // The response is always empty
9865         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
9866         completeRequest(callback, -1, null, null, '');
9867       };
9868
9869       xhr.onerror = requestError;
9870       xhr.onabort = requestError;
9871
9872       if (withCredentials) {
9873         xhr.withCredentials = true;
9874       }
9875
9876       if (responseType) {
9877         try {
9878           xhr.responseType = responseType;
9879         } catch (e) {
9880           // WebKit added support for the json responseType value on 09/03/2013
9881           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
9882           // known to throw when setting the value "json" as the response type. Other older
9883           // browsers implementing the responseType
9884           //
9885           // The json response type can be ignored if not supported, because JSON payloads are
9886           // parsed on the client-side regardless.
9887           if (responseType !== 'json') {
9888             throw e;
9889           }
9890         }
9891       }
9892
9893       xhr.send(post || null);
9894     }
9895
9896     if (timeout > 0) {
9897       var timeoutId = $browserDefer(timeoutRequest, timeout);
9898     } else if (isPromiseLike(timeout)) {
9899       timeout.then(timeoutRequest);
9900     }
9901
9902
9903     function timeoutRequest() {
9904       jsonpDone && jsonpDone();
9905       xhr && xhr.abort();
9906     }
9907
9908     function completeRequest(callback, status, response, headersString, statusText) {
9909       // cancel timeout and subsequent timeout promise resolution
9910       if (timeoutId !== undefined) {
9911         $browserDefer.cancel(timeoutId);
9912       }
9913       jsonpDone = xhr = null;
9914
9915       callback(status, response, headersString, statusText);
9916       $browser.$$completeOutstandingRequest(noop);
9917     }
9918   };
9919
9920   function jsonpReq(url, callbackId, done) {
9921     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
9922     // - fetches local scripts via XHR and evals them
9923     // - adds and immediately removes script elements from the document
9924     var script = rawDocument.createElement('script'), callback = null;
9925     script.type = "text/javascript";
9926     script.src = url;
9927     script.async = true;
9928
9929     callback = function(event) {
9930       removeEventListenerFn(script, "load", callback);
9931       removeEventListenerFn(script, "error", callback);
9932       rawDocument.body.removeChild(script);
9933       script = null;
9934       var status = -1;
9935       var text = "unknown";
9936
9937       if (event) {
9938         if (event.type === "load" && !callbacks[callbackId].called) {
9939           event = { type: "error" };
9940         }
9941         text = event.type;
9942         status = event.type === "error" ? 404 : 200;
9943       }
9944
9945       if (done) {
9946         done(status, text);
9947       }
9948     };
9949
9950     addEventListenerFn(script, "load", callback);
9951     addEventListenerFn(script, "error", callback);
9952     rawDocument.body.appendChild(script);
9953     return callback;
9954   }
9955 }
9956
9957 var $interpolateMinErr = minErr('$interpolate');
9958
9959 /**
9960  * @ngdoc provider
9961  * @name $interpolateProvider
9962  *
9963  * @description
9964  *
9965  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
9966  *
9967  * @example
9968 <example module="customInterpolationApp">
9969 <file name="index.html">
9970 <script>
9971   var customInterpolationApp = angular.module('customInterpolationApp', []);
9972
9973   customInterpolationApp.config(function($interpolateProvider) {
9974     $interpolateProvider.startSymbol('//');
9975     $interpolateProvider.endSymbol('//');
9976   });
9977
9978
9979   customInterpolationApp.controller('DemoController', function() {
9980       this.label = "This binding is brought you by // interpolation symbols.";
9981   });
9982 </script>
9983 <div ng-app="App" ng-controller="DemoController as demo">
9984     //demo.label//
9985 </div>
9986 </file>
9987 <file name="protractor.js" type="protractor">
9988   it('should interpolate binding with custom symbols', function() {
9989     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
9990   });
9991 </file>
9992 </example>
9993  */
9994 function $InterpolateProvider() {
9995   var startSymbol = '{{';
9996   var endSymbol = '}}';
9997
9998   /**
9999    * @ngdoc method
10000    * @name $interpolateProvider#startSymbol
10001    * @description
10002    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10003    *
10004    * @param {string=} value new value to set the starting symbol to.
10005    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10006    */
10007   this.startSymbol = function(value) {
10008     if (value) {
10009       startSymbol = value;
10010       return this;
10011     } else {
10012       return startSymbol;
10013     }
10014   };
10015
10016   /**
10017    * @ngdoc method
10018    * @name $interpolateProvider#endSymbol
10019    * @description
10020    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10021    *
10022    * @param {string=} value new value to set the ending symbol to.
10023    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10024    */
10025   this.endSymbol = function(value) {
10026     if (value) {
10027       endSymbol = value;
10028       return this;
10029     } else {
10030       return endSymbol;
10031     }
10032   };
10033
10034
10035   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10036     var startSymbolLength = startSymbol.length,
10037         endSymbolLength = endSymbol.length,
10038         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
10039         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
10040
10041     function escape(ch) {
10042       return '\\\\\\' + ch;
10043     }
10044
10045     /**
10046      * @ngdoc service
10047      * @name $interpolate
10048      * @kind function
10049      *
10050      * @requires $parse
10051      * @requires $sce
10052      *
10053      * @description
10054      *
10055      * Compiles a string with markup into an interpolation function. This service is used by the
10056      * HTML {@link ng.$compile $compile} service for data binding. See
10057      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
10058      * interpolation markup.
10059      *
10060      *
10061      * ```js
10062      *   var $interpolate = ...; // injected
10063      *   var exp = $interpolate('Hello {{name | uppercase}}!');
10064      *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
10065      * ```
10066      *
10067      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
10068      * `true`, the interpolation function will return `undefined` unless all embedded expressions
10069      * evaluate to a value other than `undefined`.
10070      *
10071      * ```js
10072      *   var $interpolate = ...; // injected
10073      *   var context = {greeting: 'Hello', name: undefined };
10074      *
10075      *   // default "forgiving" mode
10076      *   var exp = $interpolate('{{greeting}} {{name}}!');
10077      *   expect(exp(context)).toEqual('Hello !');
10078      *
10079      *   // "allOrNothing" mode
10080      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
10081      *   expect(exp(context)).toBeUndefined();
10082      *   context.name = 'Angular';
10083      *   expect(exp(context)).toEqual('Hello Angular!');
10084      * ```
10085      *
10086      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
10087      *
10088      * ####Escaped Interpolation
10089      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
10090      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
10091      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
10092      * or binding.
10093      *
10094      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
10095      * degree, while also enabling code examples to work without relying on the
10096      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
10097      *
10098      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
10099      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
10100      * interpolation start/end markers with their escaped counterparts.**
10101      *
10102      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
10103      * output when the $interpolate service processes the text. So, for HTML elements interpolated
10104      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
10105      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
10106      * this is typically useful only when user-data is used in rendering a template from the server, or
10107      * when otherwise untrusted data is used by a directive.
10108      *
10109      * <example>
10110      *  <file name="index.html">
10111      *    <div ng-init="username='A user'">
10112      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
10113      *        </p>
10114      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
10115      *        application, but fails to accomplish their task, because the server has correctly
10116      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
10117      *        characters.</p>
10118      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
10119      *        from the database by an administrator.</p>
10120      *    </div>
10121      *  </file>
10122      * </example>
10123      *
10124      * @param {string} text The text with markup to interpolate.
10125      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
10126      *    embedded expression in order to return an interpolation function. Strings with no
10127      *    embedded expression will return null for the interpolation function.
10128      * @param {string=} trustedContext when provided, the returned function passes the interpolated
10129      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
10130      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
10131      *    provides Strict Contextual Escaping for details.
10132      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
10133      *    unless all embedded expressions evaluate to a value other than `undefined`.
10134      * @returns {function(context)} an interpolation function which is used to compute the
10135      *    interpolated string. The function has these parameters:
10136      *
10137      * - `context`: evaluation context for all expressions embedded in the interpolated text
10138      */
10139     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
10140       allOrNothing = !!allOrNothing;
10141       var startIndex,
10142           endIndex,
10143           index = 0,
10144           expressions = [],
10145           parseFns = [],
10146           textLength = text.length,
10147           exp,
10148           concat = [],
10149           expressionPositions = [];
10150
10151       while (index < textLength) {
10152         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
10153              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
10154           if (index !== startIndex) {
10155             concat.push(unescapeText(text.substring(index, startIndex)));
10156           }
10157           exp = text.substring(startIndex + startSymbolLength, endIndex);
10158           expressions.push(exp);
10159           parseFns.push($parse(exp, parseStringifyInterceptor));
10160           index = endIndex + endSymbolLength;
10161           expressionPositions.push(concat.length);
10162           concat.push('');
10163         } else {
10164           // we did not find an interpolation, so we have to add the remainder to the separators array
10165           if (index !== textLength) {
10166             concat.push(unescapeText(text.substring(index)));
10167           }
10168           break;
10169         }
10170       }
10171
10172       // Concatenating expressions makes it hard to reason about whether some combination of
10173       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
10174       // single expression be used for iframe[src], object[src], etc., we ensure that the value
10175       // that's used is assigned or constructed by some JS code somewhere that is more testable or
10176       // make it obvious that you bound the value to some user controlled value.  This helps reduce
10177       // the load when auditing for XSS issues.
10178       if (trustedContext && concat.length > 1) {
10179           throw $interpolateMinErr('noconcat',
10180               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10181               "interpolations that concatenate multiple expressions when a trusted value is " +
10182               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10183       }
10184
10185       if (!mustHaveExpression || expressions.length) {
10186         var compute = function(values) {
10187           for (var i = 0, ii = expressions.length; i < ii; i++) {
10188             if (allOrNothing && isUndefined(values[i])) return;
10189             concat[expressionPositions[i]] = values[i];
10190           }
10191           return concat.join('');
10192         };
10193
10194         var getValue = function(value) {
10195           return trustedContext ?
10196             $sce.getTrusted(trustedContext, value) :
10197             $sce.valueOf(value);
10198         };
10199
10200         var stringify = function(value) {
10201           if (value == null) { // null || undefined
10202             return '';
10203           }
10204           switch (typeof value) {
10205             case 'string':
10206               break;
10207             case 'number':
10208               value = '' + value;
10209               break;
10210             default:
10211               value = toJson(value);
10212           }
10213
10214           return value;
10215         };
10216
10217         return extend(function interpolationFn(context) {
10218             var i = 0;
10219             var ii = expressions.length;
10220             var values = new Array(ii);
10221
10222             try {
10223               for (; i < ii; i++) {
10224                 values[i] = parseFns[i](context);
10225               }
10226
10227               return compute(values);
10228             } catch (err) {
10229               var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10230                   err.toString());
10231               $exceptionHandler(newErr);
10232             }
10233
10234           }, {
10235           // all of these properties are undocumented for now
10236           exp: text, //just for compatibility with regular watchers created via $watch
10237           expressions: expressions,
10238           $$watchDelegate: function(scope, listener, objectEquality) {
10239             var lastValue;
10240             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
10241               var currValue = compute(values);
10242               if (isFunction(listener)) {
10243                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
10244               }
10245               lastValue = currValue;
10246             }, objectEquality);
10247           }
10248         });
10249       }
10250
10251       function unescapeText(text) {
10252         return text.replace(escapedStartRegexp, startSymbol).
10253           replace(escapedEndRegexp, endSymbol);
10254       }
10255
10256       function parseStringifyInterceptor(value) {
10257         try {
10258           value = getValue(value);
10259           return allOrNothing && !isDefined(value) ? value : stringify(value);
10260         } catch (err) {
10261           var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10262             err.toString());
10263           $exceptionHandler(newErr);
10264         }
10265       }
10266     }
10267
10268
10269     /**
10270      * @ngdoc method
10271      * @name $interpolate#startSymbol
10272      * @description
10273      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
10274      *
10275      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
10276      * the symbol.
10277      *
10278      * @returns {string} start symbol.
10279      */
10280     $interpolate.startSymbol = function() {
10281       return startSymbol;
10282     };
10283
10284
10285     /**
10286      * @ngdoc method
10287      * @name $interpolate#endSymbol
10288      * @description
10289      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10290      *
10291      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
10292      * the symbol.
10293      *
10294      * @returns {string} end symbol.
10295      */
10296     $interpolate.endSymbol = function() {
10297       return endSymbol;
10298     };
10299
10300     return $interpolate;
10301   }];
10302 }
10303
10304 function $IntervalProvider() {
10305   this.$get = ['$rootScope', '$window', '$q', '$$q',
10306        function($rootScope,   $window,   $q,   $$q) {
10307     var intervals = {};
10308
10309
10310      /**
10311       * @ngdoc service
10312       * @name $interval
10313       *
10314       * @description
10315       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
10316       * milliseconds.
10317       *
10318       * The return value of registering an interval function is a promise. This promise will be
10319       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
10320       * run indefinitely if `count` is not defined. The value of the notification will be the
10321       * number of iterations that have run.
10322       * To cancel an interval, call `$interval.cancel(promise)`.
10323       *
10324       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
10325       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
10326       * time.
10327       *
10328       * <div class="alert alert-warning">
10329       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
10330       * with them.  In particular they are not automatically destroyed when a controller's scope or a
10331       * directive's element are destroyed.
10332       * You should take this into consideration and make sure to always cancel the interval at the
10333       * appropriate moment.  See the example below for more details on how and when to do this.
10334       * </div>
10335       *
10336       * @param {function()} fn A function that should be called repeatedly.
10337       * @param {number} delay Number of milliseconds between each function call.
10338       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
10339       *   indefinitely.
10340       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
10341       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
10342       * @returns {promise} A promise which will be notified on each iteration.
10343       *
10344       * @example
10345       * <example module="intervalExample">
10346       * <file name="index.html">
10347       *   <script>
10348       *     angular.module('intervalExample', [])
10349       *       .controller('ExampleController', ['$scope', '$interval',
10350       *         function($scope, $interval) {
10351       *           $scope.format = 'M/d/yy h:mm:ss a';
10352       *           $scope.blood_1 = 100;
10353       *           $scope.blood_2 = 120;
10354       *
10355       *           var stop;
10356       *           $scope.fight = function() {
10357       *             // Don't start a new fight if we are already fighting
10358       *             if ( angular.isDefined(stop) ) return;
10359       *
10360       *             stop = $interval(function() {
10361       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10362       *                 $scope.blood_1 = $scope.blood_1 - 3;
10363       *                 $scope.blood_2 = $scope.blood_2 - 4;
10364       *               } else {
10365       *                 $scope.stopFight();
10366       *               }
10367       *             }, 100);
10368       *           };
10369       *
10370       *           $scope.stopFight = function() {
10371       *             if (angular.isDefined(stop)) {
10372       *               $interval.cancel(stop);
10373       *               stop = undefined;
10374       *             }
10375       *           };
10376       *
10377       *           $scope.resetFight = function() {
10378       *             $scope.blood_1 = 100;
10379       *             $scope.blood_2 = 120;
10380       *           };
10381       *
10382       *           $scope.$on('$destroy', function() {
10383       *             // Make sure that the interval is destroyed too
10384       *             $scope.stopFight();
10385       *           });
10386       *         }])
10387       *       // Register the 'myCurrentTime' directive factory method.
10388       *       // We inject $interval and dateFilter service since the factory method is DI.
10389       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
10390       *         function($interval, dateFilter) {
10391       *           // return the directive link function. (compile function not needed)
10392       *           return function(scope, element, attrs) {
10393       *             var format,  // date format
10394       *                 stopTime; // so that we can cancel the time updates
10395       *
10396       *             // used to update the UI
10397       *             function updateTime() {
10398       *               element.text(dateFilter(new Date(), format));
10399       *             }
10400       *
10401       *             // watch the expression, and update the UI on change.
10402       *             scope.$watch(attrs.myCurrentTime, function(value) {
10403       *               format = value;
10404       *               updateTime();
10405       *             });
10406       *
10407       *             stopTime = $interval(updateTime, 1000);
10408       *
10409       *             // listen on DOM destroy (removal) event, and cancel the next UI update
10410       *             // to prevent updating time after the DOM element was removed.
10411       *             element.on('$destroy', function() {
10412       *               $interval.cancel(stopTime);
10413       *             });
10414       *           }
10415       *         }]);
10416       *   </script>
10417       *
10418       *   <div>
10419       *     <div ng-controller="ExampleController">
10420       *       Date format: <input ng-model="format"> <hr/>
10421       *       Current time is: <span my-current-time="format"></span>
10422       *       <hr/>
10423       *       Blood 1 : <font color='red'>{{blood_1}}</font>
10424       *       Blood 2 : <font color='red'>{{blood_2}}</font>
10425       *       <button type="button" data-ng-click="fight()">Fight</button>
10426       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
10427       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
10428       *     </div>
10429       *   </div>
10430       *
10431       * </file>
10432       * </example>
10433       */
10434     function interval(fn, delay, count, invokeApply) {
10435       var setInterval = $window.setInterval,
10436           clearInterval = $window.clearInterval,
10437           iteration = 0,
10438           skipApply = (isDefined(invokeApply) && !invokeApply),
10439           deferred = (skipApply ? $$q : $q).defer(),
10440           promise = deferred.promise;
10441
10442       count = isDefined(count) ? count : 0;
10443
10444       promise.then(null, null, fn);
10445
10446       promise.$$intervalId = setInterval(function tick() {
10447         deferred.notify(iteration++);
10448
10449         if (count > 0 && iteration >= count) {
10450           deferred.resolve(iteration);
10451           clearInterval(promise.$$intervalId);
10452           delete intervals[promise.$$intervalId];
10453         }
10454
10455         if (!skipApply) $rootScope.$apply();
10456
10457       }, delay);
10458
10459       intervals[promise.$$intervalId] = deferred;
10460
10461       return promise;
10462     }
10463
10464
10465      /**
10466       * @ngdoc method
10467       * @name $interval#cancel
10468       *
10469       * @description
10470       * Cancels a task associated with the `promise`.
10471       *
10472       * @param {promise} promise returned by the `$interval` function.
10473       * @returns {boolean} Returns `true` if the task was successfully canceled.
10474       */
10475     interval.cancel = function(promise) {
10476       if (promise && promise.$$intervalId in intervals) {
10477         intervals[promise.$$intervalId].reject('canceled');
10478         $window.clearInterval(promise.$$intervalId);
10479         delete intervals[promise.$$intervalId];
10480         return true;
10481       }
10482       return false;
10483     };
10484
10485     return interval;
10486   }];
10487 }
10488
10489 /**
10490  * @ngdoc service
10491  * @name $locale
10492  *
10493  * @description
10494  * $locale service provides localization rules for various Angular components. As of right now the
10495  * only public api is:
10496  *
10497  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
10498  */
10499 function $LocaleProvider() {
10500   this.$get = function() {
10501     return {
10502       id: 'en-us',
10503
10504       NUMBER_FORMATS: {
10505         DECIMAL_SEP: '.',
10506         GROUP_SEP: ',',
10507         PATTERNS: [
10508           { // Decimal Pattern
10509             minInt: 1,
10510             minFrac: 0,
10511             maxFrac: 3,
10512             posPre: '',
10513             posSuf: '',
10514             negPre: '-',
10515             negSuf: '',
10516             gSize: 3,
10517             lgSize: 3
10518           },{ //Currency Pattern
10519             minInt: 1,
10520             minFrac: 2,
10521             maxFrac: 2,
10522             posPre: '\u00A4',
10523             posSuf: '',
10524             negPre: '(\u00A4',
10525             negSuf: ')',
10526             gSize: 3,
10527             lgSize: 3
10528           }
10529         ],
10530         CURRENCY_SYM: '$'
10531       },
10532
10533       DATETIME_FORMATS: {
10534         MONTH:
10535             'January,February,March,April,May,June,July,August,September,October,November,December'
10536             .split(','),
10537         SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
10538         DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
10539         SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
10540         AMPMS: ['AM','PM'],
10541         medium: 'MMM d, y h:mm:ss a',
10542         'short': 'M/d/yy h:mm a',
10543         fullDate: 'EEEE, MMMM d, y',
10544         longDate: 'MMMM d, y',
10545         mediumDate: 'MMM d, y',
10546         shortDate: 'M/d/yy',
10547         mediumTime: 'h:mm:ss a',
10548         shortTime: 'h:mm a',
10549         ERANAMES: [
10550           "Before Christ",
10551           "Anno Domini"
10552         ],
10553         ERAS: [
10554           "BC",
10555           "AD"
10556         ]
10557       },
10558
10559       pluralCat: function(num) {
10560         if (num === 1) {
10561           return 'one';
10562         }
10563         return 'other';
10564       }
10565     };
10566   };
10567 }
10568
10569 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
10570     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
10571 var $locationMinErr = minErr('$location');
10572
10573
10574 /**
10575  * Encode path using encodeUriSegment, ignoring forward slashes
10576  *
10577  * @param {string} path Path to encode
10578  * @returns {string}
10579  */
10580 function encodePath(path) {
10581   var segments = path.split('/'),
10582       i = segments.length;
10583
10584   while (i--) {
10585     segments[i] = encodeUriSegment(segments[i]);
10586   }
10587
10588   return segments.join('/');
10589 }
10590
10591 function parseAbsoluteUrl(absoluteUrl, locationObj) {
10592   var parsedUrl = urlResolve(absoluteUrl);
10593
10594   locationObj.$$protocol = parsedUrl.protocol;
10595   locationObj.$$host = parsedUrl.hostname;
10596   locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
10597 }
10598
10599
10600 function parseAppUrl(relativeUrl, locationObj) {
10601   var prefixed = (relativeUrl.charAt(0) !== '/');
10602   if (prefixed) {
10603     relativeUrl = '/' + relativeUrl;
10604   }
10605   var match = urlResolve(relativeUrl);
10606   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
10607       match.pathname.substring(1) : match.pathname);
10608   locationObj.$$search = parseKeyValue(match.search);
10609   locationObj.$$hash = decodeURIComponent(match.hash);
10610
10611   // make sure path starts with '/';
10612   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
10613     locationObj.$$path = '/' + locationObj.$$path;
10614   }
10615 }
10616
10617
10618 /**
10619  *
10620  * @param {string} begin
10621  * @param {string} whole
10622  * @returns {string} returns text from whole after begin or undefined if it does not begin with
10623  *                   expected string.
10624  */
10625 function beginsWith(begin, whole) {
10626   if (whole.indexOf(begin) === 0) {
10627     return whole.substr(begin.length);
10628   }
10629 }
10630
10631
10632 function stripHash(url) {
10633   var index = url.indexOf('#');
10634   return index == -1 ? url : url.substr(0, index);
10635 }
10636
10637 function trimEmptyHash(url) {
10638   return url.replace(/(#.+)|#$/, '$1');
10639 }
10640
10641
10642 function stripFile(url) {
10643   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
10644 }
10645
10646 /* return the server only (scheme://host:port) */
10647 function serverBase(url) {
10648   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
10649 }
10650
10651
10652 /**
10653  * LocationHtml5Url represents an url
10654  * This object is exposed as $location service when HTML5 mode is enabled and supported
10655  *
10656  * @constructor
10657  * @param {string} appBase application base URL
10658  * @param {string} appBaseNoFile application base URL stripped of any filename
10659  * @param {string} basePrefix url path prefix
10660  */
10661 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
10662   this.$$html5 = true;
10663   basePrefix = basePrefix || '';
10664   parseAbsoluteUrl(appBase, this);
10665
10666
10667   /**
10668    * Parse given html5 (regular) url string into properties
10669    * @param {string} url HTML5 url
10670    * @private
10671    */
10672   this.$$parse = function(url) {
10673     var pathUrl = beginsWith(appBaseNoFile, url);
10674     if (!isString(pathUrl)) {
10675       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
10676           appBaseNoFile);
10677     }
10678
10679     parseAppUrl(pathUrl, this);
10680
10681     if (!this.$$path) {
10682       this.$$path = '/';
10683     }
10684
10685     this.$$compose();
10686   };
10687
10688   /**
10689    * Compose url and update `absUrl` property
10690    * @private
10691    */
10692   this.$$compose = function() {
10693     var search = toKeyValue(this.$$search),
10694         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10695
10696     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10697     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
10698   };
10699
10700   this.$$parseLinkUrl = function(url, relHref) {
10701     if (relHref && relHref[0] === '#') {
10702       // special case for links to hash fragments:
10703       // keep the old url and only replace the hash fragment
10704       this.hash(relHref.slice(1));
10705       return true;
10706     }
10707     var appUrl, prevAppUrl;
10708     var rewrittenUrl;
10709
10710     if ((appUrl = beginsWith(appBase, url)) !== undefined) {
10711       prevAppUrl = appUrl;
10712       if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
10713         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
10714       } else {
10715         rewrittenUrl = appBase + prevAppUrl;
10716       }
10717     } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
10718       rewrittenUrl = appBaseNoFile + appUrl;
10719     } else if (appBaseNoFile == url + '/') {
10720       rewrittenUrl = appBaseNoFile;
10721     }
10722     if (rewrittenUrl) {
10723       this.$$parse(rewrittenUrl);
10724     }
10725     return !!rewrittenUrl;
10726   };
10727 }
10728
10729
10730 /**
10731  * LocationHashbangUrl represents url
10732  * This object is exposed as $location service when developer doesn't opt into html5 mode.
10733  * It also serves as the base class for html5 mode fallback on legacy browsers.
10734  *
10735  * @constructor
10736  * @param {string} appBase application base URL
10737  * @param {string} appBaseNoFile application base URL stripped of any filename
10738  * @param {string} hashPrefix hashbang prefix
10739  */
10740 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
10741
10742   parseAbsoluteUrl(appBase, this);
10743
10744
10745   /**
10746    * Parse given hashbang url into properties
10747    * @param {string} url Hashbang url
10748    * @private
10749    */
10750   this.$$parse = function(url) {
10751     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
10752     var withoutHashUrl;
10753
10754     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
10755
10756       // The rest of the url starts with a hash so we have
10757       // got either a hashbang path or a plain hash fragment
10758       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
10759       if (isUndefined(withoutHashUrl)) {
10760         // There was no hashbang prefix so we just have a hash fragment
10761         withoutHashUrl = withoutBaseUrl;
10762       }
10763
10764     } else {
10765       // There was no hashbang path nor hash fragment:
10766       // If we are in HTML5 mode we use what is left as the path;
10767       // Otherwise we ignore what is left
10768       if (this.$$html5) {
10769         withoutHashUrl = withoutBaseUrl;
10770       } else {
10771         withoutHashUrl = '';
10772         if (isUndefined(withoutBaseUrl)) {
10773           appBase = url;
10774           this.replace();
10775         }
10776       }
10777     }
10778
10779     parseAppUrl(withoutHashUrl, this);
10780
10781     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
10782
10783     this.$$compose();
10784
10785     /*
10786      * In Windows, on an anchor node on documents loaded from
10787      * the filesystem, the browser will return a pathname
10788      * prefixed with the drive name ('/C:/path') when a
10789      * pathname without a drive is set:
10790      *  * a.setAttribute('href', '/foo')
10791      *   * a.pathname === '/C:/foo' //true
10792      *
10793      * Inside of Angular, we're always using pathnames that
10794      * do not include drive names for routing.
10795      */
10796     function removeWindowsDriveName(path, url, base) {
10797       /*
10798       Matches paths for file protocol on windows,
10799       such as /C:/foo/bar, and captures only /foo/bar.
10800       */
10801       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
10802
10803       var firstPathSegmentMatch;
10804
10805       //Get the relative path from the input URL.
10806       if (url.indexOf(base) === 0) {
10807         url = url.replace(base, '');
10808       }
10809
10810       // The input URL intentionally contains a first path segment that ends with a colon.
10811       if (windowsFilePathExp.exec(url)) {
10812         return path;
10813       }
10814
10815       firstPathSegmentMatch = windowsFilePathExp.exec(path);
10816       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
10817     }
10818   };
10819
10820   /**
10821    * Compose hashbang url and update `absUrl` property
10822    * @private
10823    */
10824   this.$$compose = function() {
10825     var search = toKeyValue(this.$$search),
10826         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10827
10828     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10829     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
10830   };
10831
10832   this.$$parseLinkUrl = function(url, relHref) {
10833     if (stripHash(appBase) == stripHash(url)) {
10834       this.$$parse(url);
10835       return true;
10836     }
10837     return false;
10838   };
10839 }
10840
10841
10842 /**
10843  * LocationHashbangUrl represents url
10844  * This object is exposed as $location service when html5 history api is enabled but the browser
10845  * does not support it.
10846  *
10847  * @constructor
10848  * @param {string} appBase application base URL
10849  * @param {string} appBaseNoFile application base URL stripped of any filename
10850  * @param {string} hashPrefix hashbang prefix
10851  */
10852 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
10853   this.$$html5 = true;
10854   LocationHashbangUrl.apply(this, arguments);
10855
10856   this.$$parseLinkUrl = function(url, relHref) {
10857     if (relHref && relHref[0] === '#') {
10858       // special case for links to hash fragments:
10859       // keep the old url and only replace the hash fragment
10860       this.hash(relHref.slice(1));
10861       return true;
10862     }
10863
10864     var rewrittenUrl;
10865     var appUrl;
10866
10867     if (appBase == stripHash(url)) {
10868       rewrittenUrl = url;
10869     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
10870       rewrittenUrl = appBase + hashPrefix + appUrl;
10871     } else if (appBaseNoFile === url + '/') {
10872       rewrittenUrl = appBaseNoFile;
10873     }
10874     if (rewrittenUrl) {
10875       this.$$parse(rewrittenUrl);
10876     }
10877     return !!rewrittenUrl;
10878   };
10879
10880   this.$$compose = function() {
10881     var search = toKeyValue(this.$$search),
10882         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10883
10884     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10885     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
10886     this.$$absUrl = appBase + hashPrefix + this.$$url;
10887   };
10888
10889 }
10890
10891
10892 var locationPrototype = {
10893
10894   /**
10895    * Are we in html5 mode?
10896    * @private
10897    */
10898   $$html5: false,
10899
10900   /**
10901    * Has any change been replacing?
10902    * @private
10903    */
10904   $$replace: false,
10905
10906   /**
10907    * @ngdoc method
10908    * @name $location#absUrl
10909    *
10910    * @description
10911    * This method is getter only.
10912    *
10913    * Return full url representation with all segments encoded according to rules specified in
10914    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
10915    *
10916    *
10917    * ```js
10918    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10919    * var absUrl = $location.absUrl();
10920    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
10921    * ```
10922    *
10923    * @return {string} full url
10924    */
10925   absUrl: locationGetter('$$absUrl'),
10926
10927   /**
10928    * @ngdoc method
10929    * @name $location#url
10930    *
10931    * @description
10932    * This method is getter / setter.
10933    *
10934    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
10935    *
10936    * Change path, search and hash, when called with parameter and return `$location`.
10937    *
10938    *
10939    * ```js
10940    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10941    * var url = $location.url();
10942    * // => "/some/path?foo=bar&baz=xoxo"
10943    * ```
10944    *
10945    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
10946    * @return {string} url
10947    */
10948   url: function(url) {
10949     if (isUndefined(url))
10950       return this.$$url;
10951
10952     var match = PATH_MATCH.exec(url);
10953     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
10954     if (match[2] || match[1] || url === '') this.search(match[3] || '');
10955     this.hash(match[5] || '');
10956
10957     return this;
10958   },
10959
10960   /**
10961    * @ngdoc method
10962    * @name $location#protocol
10963    *
10964    * @description
10965    * This method is getter only.
10966    *
10967    * Return protocol of current url.
10968    *
10969    *
10970    * ```js
10971    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10972    * var protocol = $location.protocol();
10973    * // => "http"
10974    * ```
10975    *
10976    * @return {string} protocol of current url
10977    */
10978   protocol: locationGetter('$$protocol'),
10979
10980   /**
10981    * @ngdoc method
10982    * @name $location#host
10983    *
10984    * @description
10985    * This method is getter only.
10986    *
10987    * Return host of current url.
10988    *
10989    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
10990    *
10991    *
10992    * ```js
10993    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10994    * var host = $location.host();
10995    * // => "example.com"
10996    *
10997    * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
10998    * host = $location.host();
10999    * // => "example.com"
11000    * host = location.host;
11001    * // => "example.com:8080"
11002    * ```
11003    *
11004    * @return {string} host of current url.
11005    */
11006   host: locationGetter('$$host'),
11007
11008   /**
11009    * @ngdoc method
11010    * @name $location#port
11011    *
11012    * @description
11013    * This method is getter only.
11014    *
11015    * Return port of current url.
11016    *
11017    *
11018    * ```js
11019    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11020    * var port = $location.port();
11021    * // => 80
11022    * ```
11023    *
11024    * @return {Number} port
11025    */
11026   port: locationGetter('$$port'),
11027
11028   /**
11029    * @ngdoc method
11030    * @name $location#path
11031    *
11032    * @description
11033    * This method is getter / setter.
11034    *
11035    * Return path of current url when called without any parameter.
11036    *
11037    * Change path when called with parameter and return `$location`.
11038    *
11039    * Note: Path should always begin with forward slash (/), this method will add the forward slash
11040    * if it is missing.
11041    *
11042    *
11043    * ```js
11044    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11045    * var path = $location.path();
11046    * // => "/some/path"
11047    * ```
11048    *
11049    * @param {(string|number)=} path New path
11050    * @return {string} path
11051    */
11052   path: locationGetterSetter('$$path', function(path) {
11053     path = path !== null ? path.toString() : '';
11054     return path.charAt(0) == '/' ? path : '/' + path;
11055   }),
11056
11057   /**
11058    * @ngdoc method
11059    * @name $location#search
11060    *
11061    * @description
11062    * This method is getter / setter.
11063    *
11064    * Return search part (as object) of current url when called without any parameter.
11065    *
11066    * Change search part when called with parameter and return `$location`.
11067    *
11068    *
11069    * ```js
11070    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11071    * var searchObject = $location.search();
11072    * // => {foo: 'bar', baz: 'xoxo'}
11073    *
11074    * // set foo to 'yipee'
11075    * $location.search('foo', 'yipee');
11076    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11077    * ```
11078    *
11079    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11080    * hash object.
11081    *
11082    * When called with a single argument the method acts as a setter, setting the `search` component
11083    * of `$location` to the specified value.
11084    *
11085    * If the argument is a hash object containing an array of values, these values will be encoded
11086    * as duplicate search parameters in the url.
11087    *
11088    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11089    * will override only a single search property.
11090    *
11091    * If `paramValue` is an array, it will override the property of the `search` component of
11092    * `$location` specified via the first argument.
11093    *
11094    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11095    *
11096    * If `paramValue` is `true`, the property specified via the first argument will be added with no
11097    * value nor trailing equal sign.
11098    *
11099    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11100    * one or more arguments returns `$location` object itself.
11101    */
11102   search: function(search, paramValue) {
11103     switch (arguments.length) {
11104       case 0:
11105         return this.$$search;
11106       case 1:
11107         if (isString(search) || isNumber(search)) {
11108           search = search.toString();
11109           this.$$search = parseKeyValue(search);
11110         } else if (isObject(search)) {
11111           search = copy(search, {});
11112           // remove object undefined or null properties
11113           forEach(search, function(value, key) {
11114             if (value == null) delete search[key];
11115           });
11116
11117           this.$$search = search;
11118         } else {
11119           throw $locationMinErr('isrcharg',
11120               'The first argument of the `$location#search()` call must be a string or an object.');
11121         }
11122         break;
11123       default:
11124         if (isUndefined(paramValue) || paramValue === null) {
11125           delete this.$$search[search];
11126         } else {
11127           this.$$search[search] = paramValue;
11128         }
11129     }
11130
11131     this.$$compose();
11132     return this;
11133   },
11134
11135   /**
11136    * @ngdoc method
11137    * @name $location#hash
11138    *
11139    * @description
11140    * This method is getter / setter.
11141    *
11142    * Return hash fragment when called without any parameter.
11143    *
11144    * Change hash fragment when called with parameter and return `$location`.
11145    *
11146    *
11147    * ```js
11148    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
11149    * var hash = $location.hash();
11150    * // => "hashValue"
11151    * ```
11152    *
11153    * @param {(string|number)=} hash New hash fragment
11154    * @return {string} hash
11155    */
11156   hash: locationGetterSetter('$$hash', function(hash) {
11157     return hash !== null ? hash.toString() : '';
11158   }),
11159
11160   /**
11161    * @ngdoc method
11162    * @name $location#replace
11163    *
11164    * @description
11165    * If called, all changes to $location during current `$digest` will be replacing current history
11166    * record, instead of adding new one.
11167    */
11168   replace: function() {
11169     this.$$replace = true;
11170     return this;
11171   }
11172 };
11173
11174 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
11175   Location.prototype = Object.create(locationPrototype);
11176
11177   /**
11178    * @ngdoc method
11179    * @name $location#state
11180    *
11181    * @description
11182    * This method is getter / setter.
11183    *
11184    * Return the history state object when called without any parameter.
11185    *
11186    * Change the history state object when called with one parameter and return `$location`.
11187    * The state object is later passed to `pushState` or `replaceState`.
11188    *
11189    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
11190    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
11191    * older browsers (like IE9 or Android < 4.0), don't use this method.
11192    *
11193    * @param {object=} state State object for pushState or replaceState
11194    * @return {object} state
11195    */
11196   Location.prototype.state = function(state) {
11197     if (!arguments.length)
11198       return this.$$state;
11199
11200     if (Location !== LocationHtml5Url || !this.$$html5) {
11201       throw $locationMinErr('nostate', 'History API state support is available only ' +
11202         'in HTML5 mode and only in browsers supporting HTML5 History API');
11203     }
11204     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
11205     // but we're changing the $$state reference to $browser.state() during the $digest
11206     // so the modification window is narrow.
11207     this.$$state = isUndefined(state) ? null : state;
11208
11209     return this;
11210   };
11211 });
11212
11213
11214 function locationGetter(property) {
11215   return function() {
11216     return this[property];
11217   };
11218 }
11219
11220
11221 function locationGetterSetter(property, preprocess) {
11222   return function(value) {
11223     if (isUndefined(value))
11224       return this[property];
11225
11226     this[property] = preprocess(value);
11227     this.$$compose();
11228
11229     return this;
11230   };
11231 }
11232
11233
11234 /**
11235  * @ngdoc service
11236  * @name $location
11237  *
11238  * @requires $rootElement
11239  *
11240  * @description
11241  * The $location service parses the URL in the browser address bar (based on the
11242  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
11243  * available to your application. Changes to the URL in the address bar are reflected into
11244  * $location service and changes to $location are reflected into the browser address bar.
11245  *
11246  * **The $location service:**
11247  *
11248  * - Exposes the current URL in the browser address bar, so you can
11249  *   - Watch and observe the URL.
11250  *   - Change the URL.
11251  * - Synchronizes the URL with the browser when the user
11252  *   - Changes the address bar.
11253  *   - Clicks the back or forward button (or clicks a History link).
11254  *   - Clicks on a link.
11255  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
11256  *
11257  * For more information see {@link guide/$location Developer Guide: Using $location}
11258  */
11259
11260 /**
11261  * @ngdoc provider
11262  * @name $locationProvider
11263  * @description
11264  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
11265  */
11266 function $LocationProvider() {
11267   var hashPrefix = '',
11268       html5Mode = {
11269         enabled: false,
11270         requireBase: true,
11271         rewriteLinks: true
11272       };
11273
11274   /**
11275    * @ngdoc method
11276    * @name $locationProvider#hashPrefix
11277    * @description
11278    * @param {string=} prefix Prefix for hash part (containing path and search)
11279    * @returns {*} current value if used as getter or itself (chaining) if used as setter
11280    */
11281   this.hashPrefix = function(prefix) {
11282     if (isDefined(prefix)) {
11283       hashPrefix = prefix;
11284       return this;
11285     } else {
11286       return hashPrefix;
11287     }
11288   };
11289
11290   /**
11291    * @ngdoc method
11292    * @name $locationProvider#html5Mode
11293    * @description
11294    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
11295    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
11296    *   properties:
11297    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
11298    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
11299    *     support `pushState`.
11300    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
11301    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
11302    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
11303    *     See the {@link guide/$location $location guide for more information}
11304    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
11305    *     enables/disables url rewriting for relative links.
11306    *
11307    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
11308    */
11309   this.html5Mode = function(mode) {
11310     if (isBoolean(mode)) {
11311       html5Mode.enabled = mode;
11312       return this;
11313     } else if (isObject(mode)) {
11314
11315       if (isBoolean(mode.enabled)) {
11316         html5Mode.enabled = mode.enabled;
11317       }
11318
11319       if (isBoolean(mode.requireBase)) {
11320         html5Mode.requireBase = mode.requireBase;
11321       }
11322
11323       if (isBoolean(mode.rewriteLinks)) {
11324         html5Mode.rewriteLinks = mode.rewriteLinks;
11325       }
11326
11327       return this;
11328     } else {
11329       return html5Mode;
11330     }
11331   };
11332
11333   /**
11334    * @ngdoc event
11335    * @name $location#$locationChangeStart
11336    * @eventType broadcast on root scope
11337    * @description
11338    * Broadcasted before a URL will change.
11339    *
11340    * This change can be prevented by calling
11341    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
11342    * details about event object. Upon successful change
11343    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
11344    *
11345    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11346    * the browser supports the HTML5 History API.
11347    *
11348    * @param {Object} angularEvent Synthetic event object.
11349    * @param {string} newUrl New URL
11350    * @param {string=} oldUrl URL that was before it was changed.
11351    * @param {string=} newState New history state object
11352    * @param {string=} oldState History state object that was before it was changed.
11353    */
11354
11355   /**
11356    * @ngdoc event
11357    * @name $location#$locationChangeSuccess
11358    * @eventType broadcast on root scope
11359    * @description
11360    * Broadcasted after a URL was changed.
11361    *
11362    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11363    * the browser supports the HTML5 History API.
11364    *
11365    * @param {Object} angularEvent Synthetic event object.
11366    * @param {string} newUrl New URL
11367    * @param {string=} oldUrl URL that was before it was changed.
11368    * @param {string=} newState New history state object
11369    * @param {string=} oldState History state object that was before it was changed.
11370    */
11371
11372   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
11373       function($rootScope, $browser, $sniffer, $rootElement, $window) {
11374     var $location,
11375         LocationMode,
11376         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
11377         initialUrl = $browser.url(),
11378         appBase;
11379
11380     if (html5Mode.enabled) {
11381       if (!baseHref && html5Mode.requireBase) {
11382         throw $locationMinErr('nobase',
11383           "$location in HTML5 mode requires a <base> tag to be present!");
11384       }
11385       appBase = serverBase(initialUrl) + (baseHref || '/');
11386       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
11387     } else {
11388       appBase = stripHash(initialUrl);
11389       LocationMode = LocationHashbangUrl;
11390     }
11391     var appBaseNoFile = stripFile(appBase);
11392
11393     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
11394     $location.$$parseLinkUrl(initialUrl, initialUrl);
11395
11396     $location.$$state = $browser.state();
11397
11398     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
11399
11400     function setBrowserUrlWithFallback(url, replace, state) {
11401       var oldUrl = $location.url();
11402       var oldState = $location.$$state;
11403       try {
11404         $browser.url(url, replace, state);
11405
11406         // Make sure $location.state() returns referentially identical (not just deeply equal)
11407         // state object; this makes possible quick checking if the state changed in the digest
11408         // loop. Checking deep equality would be too expensive.
11409         $location.$$state = $browser.state();
11410       } catch (e) {
11411         // Restore old values if pushState fails
11412         $location.url(oldUrl);
11413         $location.$$state = oldState;
11414
11415         throw e;
11416       }
11417     }
11418
11419     $rootElement.on('click', function(event) {
11420       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
11421       // currently we open nice url link and redirect then
11422
11423       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
11424
11425       var elm = jqLite(event.target);
11426
11427       // traverse the DOM up to find first A tag
11428       while (nodeName_(elm[0]) !== 'a') {
11429         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
11430         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
11431       }
11432
11433       var absHref = elm.prop('href');
11434       // get the actual href attribute - see
11435       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
11436       var relHref = elm.attr('href') || elm.attr('xlink:href');
11437
11438       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
11439         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
11440         // an animation.
11441         absHref = urlResolve(absHref.animVal).href;
11442       }
11443
11444       // Ignore when url is started with javascript: or mailto:
11445       if (IGNORE_URI_REGEXP.test(absHref)) return;
11446
11447       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
11448         if ($location.$$parseLinkUrl(absHref, relHref)) {
11449           // We do a preventDefault for all urls that are part of the angular application,
11450           // in html5mode and also without, so that we are able to abort navigation without
11451           // getting double entries in the location history.
11452           event.preventDefault();
11453           // update location manually
11454           if ($location.absUrl() != $browser.url()) {
11455             $rootScope.$apply();
11456             // hack to work around FF6 bug 684208 when scenario runner clicks on links
11457             $window.angular['ff-684208-preventDefault'] = true;
11458           }
11459         }
11460       }
11461     });
11462
11463
11464     // rewrite hashbang url <> html5 url
11465     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
11466       $browser.url($location.absUrl(), true);
11467     }
11468
11469     var initializing = true;
11470
11471     // update $location when $browser url changes
11472     $browser.onUrlChange(function(newUrl, newState) {
11473
11474       if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
11475         // If we are navigating outside of the app then force a reload
11476         $window.location.href = newUrl;
11477         return;
11478       }
11479
11480       $rootScope.$evalAsync(function() {
11481         var oldUrl = $location.absUrl();
11482         var oldState = $location.$$state;
11483         var defaultPrevented;
11484
11485         $location.$$parse(newUrl);
11486         $location.$$state = newState;
11487
11488         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11489             newState, oldState).defaultPrevented;
11490
11491         // if the location was changed by a `$locationChangeStart` handler then stop
11492         // processing this location change
11493         if ($location.absUrl() !== newUrl) return;
11494
11495         if (defaultPrevented) {
11496           $location.$$parse(oldUrl);
11497           $location.$$state = oldState;
11498           setBrowserUrlWithFallback(oldUrl, false, oldState);
11499         } else {
11500           initializing = false;
11501           afterLocationChange(oldUrl, oldState);
11502         }
11503       });
11504       if (!$rootScope.$$phase) $rootScope.$digest();
11505     });
11506
11507     // update browser
11508     $rootScope.$watch(function $locationWatch() {
11509       var oldUrl = trimEmptyHash($browser.url());
11510       var newUrl = trimEmptyHash($location.absUrl());
11511       var oldState = $browser.state();
11512       var currentReplace = $location.$$replace;
11513       var urlOrStateChanged = oldUrl !== newUrl ||
11514         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
11515
11516       if (initializing || urlOrStateChanged) {
11517         initializing = false;
11518
11519         $rootScope.$evalAsync(function() {
11520           var newUrl = $location.absUrl();
11521           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11522               $location.$$state, oldState).defaultPrevented;
11523
11524           // if the location was changed by a `$locationChangeStart` handler then stop
11525           // processing this location change
11526           if ($location.absUrl() !== newUrl) return;
11527
11528           if (defaultPrevented) {
11529             $location.$$parse(oldUrl);
11530             $location.$$state = oldState;
11531           } else {
11532             if (urlOrStateChanged) {
11533               setBrowserUrlWithFallback(newUrl, currentReplace,
11534                                         oldState === $location.$$state ? null : $location.$$state);
11535             }
11536             afterLocationChange(oldUrl, oldState);
11537           }
11538         });
11539       }
11540
11541       $location.$$replace = false;
11542
11543       // we don't need to return anything because $evalAsync will make the digest loop dirty when
11544       // there is a change
11545     });
11546
11547     return $location;
11548
11549     function afterLocationChange(oldUrl, oldState) {
11550       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
11551         $location.$$state, oldState);
11552     }
11553 }];
11554 }
11555
11556 /**
11557  * @ngdoc service
11558  * @name $log
11559  * @requires $window
11560  *
11561  * @description
11562  * Simple service for logging. Default implementation safely writes the message
11563  * into the browser's console (if present).
11564  *
11565  * The main purpose of this service is to simplify debugging and troubleshooting.
11566  *
11567  * The default is to log `debug` messages. You can use
11568  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
11569  *
11570  * @example
11571    <example module="logExample">
11572      <file name="script.js">
11573        angular.module('logExample', [])
11574          .controller('LogController', ['$scope', '$log', function($scope, $log) {
11575            $scope.$log = $log;
11576            $scope.message = 'Hello World!';
11577          }]);
11578      </file>
11579      <file name="index.html">
11580        <div ng-controller="LogController">
11581          <p>Reload this page with open console, enter text and hit the log button...</p>
11582          Message:
11583          <input type="text" ng-model="message"/>
11584          <button ng-click="$log.log(message)">log</button>
11585          <button ng-click="$log.warn(message)">warn</button>
11586          <button ng-click="$log.info(message)">info</button>
11587          <button ng-click="$log.error(message)">error</button>
11588          <button ng-click="$log.debug(message)">debug</button>
11589        </div>
11590      </file>
11591    </example>
11592  */
11593
11594 /**
11595  * @ngdoc provider
11596  * @name $logProvider
11597  * @description
11598  * Use the `$logProvider` to configure how the application logs messages
11599  */
11600 function $LogProvider() {
11601   var debug = true,
11602       self = this;
11603
11604   /**
11605    * @ngdoc method
11606    * @name $logProvider#debugEnabled
11607    * @description
11608    * @param {boolean=} flag enable or disable debug level messages
11609    * @returns {*} current value if used as getter or itself (chaining) if used as setter
11610    */
11611   this.debugEnabled = function(flag) {
11612     if (isDefined(flag)) {
11613       debug = flag;
11614     return this;
11615     } else {
11616       return debug;
11617     }
11618   };
11619
11620   this.$get = ['$window', function($window) {
11621     return {
11622       /**
11623        * @ngdoc method
11624        * @name $log#log
11625        *
11626        * @description
11627        * Write a log message
11628        */
11629       log: consoleLog('log'),
11630
11631       /**
11632        * @ngdoc method
11633        * @name $log#info
11634        *
11635        * @description
11636        * Write an information message
11637        */
11638       info: consoleLog('info'),
11639
11640       /**
11641        * @ngdoc method
11642        * @name $log#warn
11643        *
11644        * @description
11645        * Write a warning message
11646        */
11647       warn: consoleLog('warn'),
11648
11649       /**
11650        * @ngdoc method
11651        * @name $log#error
11652        *
11653        * @description
11654        * Write an error message
11655        */
11656       error: consoleLog('error'),
11657
11658       /**
11659        * @ngdoc method
11660        * @name $log#debug
11661        *
11662        * @description
11663        * Write a debug message
11664        */
11665       debug: (function() {
11666         var fn = consoleLog('debug');
11667
11668         return function() {
11669           if (debug) {
11670             fn.apply(self, arguments);
11671           }
11672         };
11673       }())
11674     };
11675
11676     function formatError(arg) {
11677       if (arg instanceof Error) {
11678         if (arg.stack) {
11679           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
11680               ? 'Error: ' + arg.message + '\n' + arg.stack
11681               : arg.stack;
11682         } else if (arg.sourceURL) {
11683           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
11684         }
11685       }
11686       return arg;
11687     }
11688
11689     function consoleLog(type) {
11690       var console = $window.console || {},
11691           logFn = console[type] || console.log || noop,
11692           hasApply = false;
11693
11694       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
11695       // The reason behind this is that console.log has type "object" in IE8...
11696       try {
11697         hasApply = !!logFn.apply;
11698       } catch (e) {}
11699
11700       if (hasApply) {
11701         return function() {
11702           var args = [];
11703           forEach(arguments, function(arg) {
11704             args.push(formatError(arg));
11705           });
11706           return logFn.apply(console, args);
11707         };
11708       }
11709
11710       // we are IE which either doesn't have window.console => this is noop and we do nothing,
11711       // or we are IE where console.log doesn't have apply so we log at least first 2 args
11712       return function(arg1, arg2) {
11713         logFn(arg1, arg2 == null ? '' : arg2);
11714       };
11715     }
11716   }];
11717 }
11718
11719 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11720  *     Any commits to this file should be reviewed with security in mind.  *
11721  *   Changes to this file can potentially create security vulnerabilities. *
11722  *          An approval from 2 Core members with history of modifying      *
11723  *                         this file is required.                          *
11724  *                                                                         *
11725  *  Does the change somehow allow for arbitrary javascript to be executed? *
11726  *    Or allows for someone to change the prototype of built-in objects?   *
11727  *     Or gives undesired access to variables likes document or window?    *
11728  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11729
11730 var $parseMinErr = minErr('$parse');
11731
11732 // Sandboxing Angular Expressions
11733 // ------------------------------
11734 // Angular expressions are generally considered safe because these expressions only have direct
11735 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
11736 // obtaining a reference to native JS functions such as the Function constructor.
11737 //
11738 // As an example, consider the following Angular expression:
11739 //
11740 //   {}.toString.constructor('alert("evil JS code")')
11741 //
11742 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
11743 // against the expression language, but not to prevent exploits that were enabled by exposing
11744 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
11745 // practice and therefore we are not even trying to protect against interaction with an object
11746 // explicitly exposed in this way.
11747 //
11748 // In general, it is not possible to access a Window object from an angular expression unless a
11749 // window or some DOM object that has a reference to window is published onto a Scope.
11750 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
11751 // native objects.
11752 //
11753 // See https://docs.angularjs.org/guide/security
11754
11755
11756 function ensureSafeMemberName(name, fullExpression) {
11757   if (name === "__defineGetter__" || name === "__defineSetter__"
11758       || name === "__lookupGetter__" || name === "__lookupSetter__"
11759       || name === "__proto__") {
11760     throw $parseMinErr('isecfld',
11761         'Attempting to access a disallowed field in Angular expressions! '
11762         + 'Expression: {0}', fullExpression);
11763   }
11764   return name;
11765 }
11766
11767 function getStringValue(name, fullExpression) {
11768   // From the JavaScript docs:
11769   // Property names must be strings. This means that non-string objects cannot be used
11770   // as keys in an object. Any non-string object, including a number, is typecasted
11771   // into a string via the toString method.
11772   //
11773   // So, to ensure that we are checking the same `name` that JavaScript would use,
11774   // we cast it to a string, if possible.
11775   // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
11776   // this is, this will handle objects that misbehave.
11777   name = name + '';
11778   if (!isString(name)) {
11779     throw $parseMinErr('iseccst',
11780         'Cannot convert object to primitive value! '
11781         + 'Expression: {0}', fullExpression);
11782   }
11783   return name;
11784 }
11785
11786 function ensureSafeObject(obj, fullExpression) {
11787   // nifty check if obj is Function that is fast and works across iframes and other contexts
11788   if (obj) {
11789     if (obj.constructor === obj) {
11790       throw $parseMinErr('isecfn',
11791           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11792           fullExpression);
11793     } else if (// isWindow(obj)
11794         obj.window === obj) {
11795       throw $parseMinErr('isecwindow',
11796           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
11797           fullExpression);
11798     } else if (// isElement(obj)
11799         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
11800       throw $parseMinErr('isecdom',
11801           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
11802           fullExpression);
11803     } else if (// block Object so that we can't get hold of dangerous Object.* methods
11804         obj === Object) {
11805       throw $parseMinErr('isecobj',
11806           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
11807           fullExpression);
11808     }
11809   }
11810   return obj;
11811 }
11812
11813 var CALL = Function.prototype.call;
11814 var APPLY = Function.prototype.apply;
11815 var BIND = Function.prototype.bind;
11816
11817 function ensureSafeFunction(obj, fullExpression) {
11818   if (obj) {
11819     if (obj.constructor === obj) {
11820       throw $parseMinErr('isecfn',
11821         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11822         fullExpression);
11823     } else if (obj === CALL || obj === APPLY || obj === BIND) {
11824       throw $parseMinErr('isecff',
11825         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
11826         fullExpression);
11827     }
11828   }
11829 }
11830
11831 //Keyword constants
11832 var CONSTANTS = createMap();
11833 forEach({
11834   'null': function() { return null; },
11835   'true': function() { return true; },
11836   'false': function() { return false; },
11837   'undefined': function() {}
11838 }, function(constantGetter, name) {
11839   constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true;
11840   CONSTANTS[name] = constantGetter;
11841 });
11842
11843 //Not quite a constant, but can be lex/parsed the same
11844 CONSTANTS['this'] = function(self) { return self; };
11845 CONSTANTS['this'].sharedGetter = true;
11846
11847
11848 //Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
11849 var OPERATORS = extend(createMap(), {
11850     '+':function(self, locals, a, b) {
11851       a=a(self, locals); b=b(self, locals);
11852       if (isDefined(a)) {
11853         if (isDefined(b)) {
11854           return a + b;
11855         }
11856         return a;
11857       }
11858       return isDefined(b) ? b : undefined;},
11859     '-':function(self, locals, a, b) {
11860           a=a(self, locals); b=b(self, locals);
11861           return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
11862         },
11863     '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
11864     '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
11865     '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
11866     '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
11867     '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
11868     '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
11869     '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
11870     '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
11871     '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
11872     '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
11873     '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
11874     '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
11875     '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
11876     '!':function(self, locals, a) {return !a(self, locals);},
11877
11878     //Tokenized as operators but parsed as assignment/filters
11879     '=':true,
11880     '|':true
11881 });
11882 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
11883
11884
11885 /////////////////////////////////////////
11886
11887
11888 /**
11889  * @constructor
11890  */
11891 var Lexer = function(options) {
11892   this.options = options;
11893 };
11894
11895 Lexer.prototype = {
11896   constructor: Lexer,
11897
11898   lex: function(text) {
11899     this.text = text;
11900     this.index = 0;
11901     this.tokens = [];
11902
11903     while (this.index < this.text.length) {
11904       var ch = this.text.charAt(this.index);
11905       if (ch === '"' || ch === "'") {
11906         this.readString(ch);
11907       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
11908         this.readNumber();
11909       } else if (this.isIdent(ch)) {
11910         this.readIdent();
11911       } else if (this.is(ch, '(){}[].,;:?')) {
11912         this.tokens.push({index: this.index, text: ch});
11913         this.index++;
11914       } else if (this.isWhitespace(ch)) {
11915         this.index++;
11916       } else {
11917         var ch2 = ch + this.peek();
11918         var ch3 = ch2 + this.peek(2);
11919         var op1 = OPERATORS[ch];
11920         var op2 = OPERATORS[ch2];
11921         var op3 = OPERATORS[ch3];
11922         if (op1 || op2 || op3) {
11923           var token = op3 ? ch3 : (op2 ? ch2 : ch);
11924           this.tokens.push({index: this.index, text: token, operator: true});
11925           this.index += token.length;
11926         } else {
11927           this.throwError('Unexpected next character ', this.index, this.index + 1);
11928         }
11929       }
11930     }
11931     return this.tokens;
11932   },
11933
11934   is: function(ch, chars) {
11935     return chars.indexOf(ch) !== -1;
11936   },
11937
11938   peek: function(i) {
11939     var num = i || 1;
11940     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
11941   },
11942
11943   isNumber: function(ch) {
11944     return ('0' <= ch && ch <= '9') && typeof ch === "string";
11945   },
11946
11947   isWhitespace: function(ch) {
11948     // IE treats non-breaking space as \u00A0
11949     return (ch === ' ' || ch === '\r' || ch === '\t' ||
11950             ch === '\n' || ch === '\v' || ch === '\u00A0');
11951   },
11952
11953   isIdent: function(ch) {
11954     return ('a' <= ch && ch <= 'z' ||
11955             'A' <= ch && ch <= 'Z' ||
11956             '_' === ch || ch === '$');
11957   },
11958
11959   isExpOperator: function(ch) {
11960     return (ch === '-' || ch === '+' || this.isNumber(ch));
11961   },
11962
11963   throwError: function(error, start, end) {
11964     end = end || this.index;
11965     var colStr = (isDefined(start)
11966             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
11967             : ' ' + end);
11968     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
11969         error, colStr, this.text);
11970   },
11971
11972   readNumber: function() {
11973     var number = '';
11974     var start = this.index;
11975     while (this.index < this.text.length) {
11976       var ch = lowercase(this.text.charAt(this.index));
11977       if (ch == '.' || this.isNumber(ch)) {
11978         number += ch;
11979       } else {
11980         var peekCh = this.peek();
11981         if (ch == 'e' && this.isExpOperator(peekCh)) {
11982           number += ch;
11983         } else if (this.isExpOperator(ch) &&
11984             peekCh && this.isNumber(peekCh) &&
11985             number.charAt(number.length - 1) == 'e') {
11986           number += ch;
11987         } else if (this.isExpOperator(ch) &&
11988             (!peekCh || !this.isNumber(peekCh)) &&
11989             number.charAt(number.length - 1) == 'e') {
11990           this.throwError('Invalid exponent');
11991         } else {
11992           break;
11993         }
11994       }
11995       this.index++;
11996     }
11997     this.tokens.push({
11998       index: start,
11999       text: number,
12000       constant: true,
12001       value: Number(number)
12002     });
12003   },
12004
12005   readIdent: function() {
12006     var start = this.index;
12007     while (this.index < this.text.length) {
12008       var ch = this.text.charAt(this.index);
12009       if (!(this.isIdent(ch) || this.isNumber(ch))) {
12010         break;
12011       }
12012       this.index++;
12013     }
12014     this.tokens.push({
12015       index: start,
12016       text: this.text.slice(start, this.index),
12017       identifier: true
12018     });
12019   },
12020
12021   readString: function(quote) {
12022     var start = this.index;
12023     this.index++;
12024     var string = '';
12025     var rawString = quote;
12026     var escape = false;
12027     while (this.index < this.text.length) {
12028       var ch = this.text.charAt(this.index);
12029       rawString += ch;
12030       if (escape) {
12031         if (ch === 'u') {
12032           var hex = this.text.substring(this.index + 1, this.index + 5);
12033           if (!hex.match(/[\da-f]{4}/i))
12034             this.throwError('Invalid unicode escape [\\u' + hex + ']');
12035           this.index += 4;
12036           string += String.fromCharCode(parseInt(hex, 16));
12037         } else {
12038           var rep = ESCAPE[ch];
12039           string = string + (rep || ch);
12040         }
12041         escape = false;
12042       } else if (ch === '\\') {
12043         escape = true;
12044       } else if (ch === quote) {
12045         this.index++;
12046         this.tokens.push({
12047           index: start,
12048           text: rawString,
12049           constant: true,
12050           value: string
12051         });
12052         return;
12053       } else {
12054         string += ch;
12055       }
12056       this.index++;
12057     }
12058     this.throwError('Unterminated quote', start);
12059   }
12060 };
12061
12062
12063 function isConstant(exp) {
12064   return exp.constant;
12065 }
12066
12067 /**
12068  * @constructor
12069  */
12070 var Parser = function(lexer, $filter, options) {
12071   this.lexer = lexer;
12072   this.$filter = $filter;
12073   this.options = options;
12074 };
12075
12076 Parser.ZERO = extend(function() {
12077   return 0;
12078 }, {
12079   sharedGetter: true,
12080   constant: true
12081 });
12082
12083 Parser.prototype = {
12084   constructor: Parser,
12085
12086   parse: function(text) {
12087     this.text = text;
12088     this.tokens = this.lexer.lex(text);
12089
12090     var value = this.statements();
12091
12092     if (this.tokens.length !== 0) {
12093       this.throwError('is an unexpected token', this.tokens[0]);
12094     }
12095
12096     value.literal = !!value.literal;
12097     value.constant = !!value.constant;
12098
12099     return value;
12100   },
12101
12102   primary: function() {
12103     var primary;
12104     if (this.expect('(')) {
12105       primary = this.filterChain();
12106       this.consume(')');
12107     } else if (this.expect('[')) {
12108       primary = this.arrayDeclaration();
12109     } else if (this.expect('{')) {
12110       primary = this.object();
12111     } else if (this.peek().identifier && this.peek().text in CONSTANTS) {
12112       primary = CONSTANTS[this.consume().text];
12113     } else if (this.peek().identifier) {
12114       primary = this.identifier();
12115     } else if (this.peek().constant) {
12116       primary = this.constant();
12117     } else {
12118       this.throwError('not a primary expression', this.peek());
12119     }
12120
12121     var next, context;
12122     while ((next = this.expect('(', '[', '.'))) {
12123       if (next.text === '(') {
12124         primary = this.functionCall(primary, context);
12125         context = null;
12126       } else if (next.text === '[') {
12127         context = primary;
12128         primary = this.objectIndex(primary);
12129       } else if (next.text === '.') {
12130         context = primary;
12131         primary = this.fieldAccess(primary);
12132       } else {
12133         this.throwError('IMPOSSIBLE');
12134       }
12135     }
12136     return primary;
12137   },
12138
12139   throwError: function(msg, token) {
12140     throw $parseMinErr('syntax',
12141         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
12142           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
12143   },
12144
12145   peekToken: function() {
12146     if (this.tokens.length === 0)
12147       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12148     return this.tokens[0];
12149   },
12150
12151   peek: function(e1, e2, e3, e4) {
12152     return this.peekAhead(0, e1, e2, e3, e4);
12153   },
12154   peekAhead: function(i, e1, e2, e3, e4) {
12155     if (this.tokens.length > i) {
12156       var token = this.tokens[i];
12157       var t = token.text;
12158       if (t === e1 || t === e2 || t === e3 || t === e4 ||
12159           (!e1 && !e2 && !e3 && !e4)) {
12160         return token;
12161       }
12162     }
12163     return false;
12164   },
12165
12166   expect: function(e1, e2, e3, e4) {
12167     var token = this.peek(e1, e2, e3, e4);
12168     if (token) {
12169       this.tokens.shift();
12170       return token;
12171     }
12172     return false;
12173   },
12174
12175   consume: function(e1) {
12176     if (this.tokens.length === 0) {
12177       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12178     }
12179
12180     var token = this.expect(e1);
12181     if (!token) {
12182       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
12183     }
12184     return token;
12185   },
12186
12187   unaryFn: function(op, right) {
12188     var fn = OPERATORS[op];
12189     return extend(function $parseUnaryFn(self, locals) {
12190       return fn(self, locals, right);
12191     }, {
12192       constant:right.constant,
12193       inputs: [right]
12194     });
12195   },
12196
12197   binaryFn: function(left, op, right, isBranching) {
12198     var fn = OPERATORS[op];
12199     return extend(function $parseBinaryFn(self, locals) {
12200       return fn(self, locals, left, right);
12201     }, {
12202       constant: left.constant && right.constant,
12203       inputs: !isBranching && [left, right]
12204     });
12205   },
12206
12207   identifier: function() {
12208     var id = this.consume().text;
12209
12210     //Continue reading each `.identifier` unless it is a method invocation
12211     while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
12212       id += this.consume().text + this.consume().text;
12213     }
12214
12215     return getterFn(id, this.options, this.text);
12216   },
12217
12218   constant: function() {
12219     var value = this.consume().value;
12220
12221     return extend(function $parseConstant() {
12222       return value;
12223     }, {
12224       constant: true,
12225       literal: true
12226     });
12227   },
12228
12229   statements: function() {
12230     var statements = [];
12231     while (true) {
12232       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12233         statements.push(this.filterChain());
12234       if (!this.expect(';')) {
12235         // optimize for the common case where there is only one statement.
12236         // TODO(size): maybe we should not support multiple statements?
12237         return (statements.length === 1)
12238             ? statements[0]
12239             : function $parseStatements(self, locals) {
12240                 var value;
12241                 for (var i = 0, ii = statements.length; i < ii; i++) {
12242                   value = statements[i](self, locals);
12243                 }
12244                 return value;
12245               };
12246       }
12247     }
12248   },
12249
12250   filterChain: function() {
12251     var left = this.expression();
12252     var token;
12253     while ((token = this.expect('|'))) {
12254       left = this.filter(left);
12255     }
12256     return left;
12257   },
12258
12259   filter: function(inputFn) {
12260     var fn = this.$filter(this.consume().text);
12261     var argsFn;
12262     var args;
12263
12264     if (this.peek(':')) {
12265       argsFn = [];
12266       args = []; // we can safely reuse the array
12267       while (this.expect(':')) {
12268         argsFn.push(this.expression());
12269       }
12270     }
12271
12272     var inputs = [inputFn].concat(argsFn || []);
12273
12274     return extend(function $parseFilter(self, locals) {
12275       var input = inputFn(self, locals);
12276       if (args) {
12277         args[0] = input;
12278
12279         var i = argsFn.length;
12280         while (i--) {
12281           args[i + 1] = argsFn[i](self, locals);
12282         }
12283
12284         return fn.apply(undefined, args);
12285       }
12286
12287       return fn(input);
12288     }, {
12289       constant: !fn.$stateful && inputs.every(isConstant),
12290       inputs: !fn.$stateful && inputs
12291     });
12292   },
12293
12294   expression: function() {
12295     return this.assignment();
12296   },
12297
12298   assignment: function() {
12299     var left = this.ternary();
12300     var right;
12301     var token;
12302     if ((token = this.expect('='))) {
12303       if (!left.assign) {
12304         this.throwError('implies assignment but [' +
12305             this.text.substring(0, token.index) + '] can not be assigned to', token);
12306       }
12307       right = this.ternary();
12308       return extend(function $parseAssignment(scope, locals) {
12309         return left.assign(scope, right(scope, locals), locals);
12310       }, {
12311         inputs: [left, right]
12312       });
12313     }
12314     return left;
12315   },
12316
12317   ternary: function() {
12318     var left = this.logicalOR();
12319     var middle;
12320     var token;
12321     if ((token = this.expect('?'))) {
12322       middle = this.assignment();
12323       if (this.consume(':')) {
12324         var right = this.assignment();
12325
12326         return extend(function $parseTernary(self, locals) {
12327           return left(self, locals) ? middle(self, locals) : right(self, locals);
12328         }, {
12329           constant: left.constant && middle.constant && right.constant
12330         });
12331       }
12332     }
12333
12334     return left;
12335   },
12336
12337   logicalOR: function() {
12338     var left = this.logicalAND();
12339     var token;
12340     while ((token = this.expect('||'))) {
12341       left = this.binaryFn(left, token.text, this.logicalAND(), true);
12342     }
12343     return left;
12344   },
12345
12346   logicalAND: function() {
12347     var left = this.equality();
12348     var token;
12349     while ((token = this.expect('&&'))) {
12350       left = this.binaryFn(left, token.text, this.equality(), true);
12351     }
12352     return left;
12353   },
12354
12355   equality: function() {
12356     var left = this.relational();
12357     var token;
12358     while ((token = this.expect('==','!=','===','!=='))) {
12359       left = this.binaryFn(left, token.text, this.relational());
12360     }
12361     return left;
12362   },
12363
12364   relational: function() {
12365     var left = this.additive();
12366     var token;
12367     while ((token = this.expect('<', '>', '<=', '>='))) {
12368       left = this.binaryFn(left, token.text, this.additive());
12369     }
12370     return left;
12371   },
12372
12373   additive: function() {
12374     var left = this.multiplicative();
12375     var token;
12376     while ((token = this.expect('+','-'))) {
12377       left = this.binaryFn(left, token.text, this.multiplicative());
12378     }
12379     return left;
12380   },
12381
12382   multiplicative: function() {
12383     var left = this.unary();
12384     var token;
12385     while ((token = this.expect('*','/','%'))) {
12386       left = this.binaryFn(left, token.text, this.unary());
12387     }
12388     return left;
12389   },
12390
12391   unary: function() {
12392     var token;
12393     if (this.expect('+')) {
12394       return this.primary();
12395     } else if ((token = this.expect('-'))) {
12396       return this.binaryFn(Parser.ZERO, token.text, this.unary());
12397     } else if ((token = this.expect('!'))) {
12398       return this.unaryFn(token.text, this.unary());
12399     } else {
12400       return this.primary();
12401     }
12402   },
12403
12404   fieldAccess: function(object) {
12405     var getter = this.identifier();
12406
12407     return extend(function $parseFieldAccess(scope, locals, self) {
12408       var o = self || object(scope, locals);
12409       return (o == null) ? undefined : getter(o);
12410     }, {
12411       assign: function(scope, value, locals) {
12412         var o = object(scope, locals);
12413         if (!o) object.assign(scope, o = {}, locals);
12414         return getter.assign(o, value);
12415       }
12416     });
12417   },
12418
12419   objectIndex: function(obj) {
12420     var expression = this.text;
12421
12422     var indexFn = this.expression();
12423     this.consume(']');
12424
12425     return extend(function $parseObjectIndex(self, locals) {
12426       var o = obj(self, locals),
12427           i = getStringValue(indexFn(self, locals), expression),
12428           v;
12429
12430       ensureSafeMemberName(i, expression);
12431       if (!o) return undefined;
12432       v = ensureSafeObject(o[i], expression);
12433       return v;
12434     }, {
12435       assign: function(self, value, locals) {
12436         var key = ensureSafeMemberName(getStringValue(indexFn(self, locals), expression), expression);
12437         // prevent overwriting of Function.constructor which would break ensureSafeObject check
12438         var o = ensureSafeObject(obj(self, locals), expression);
12439         if (!o) obj.assign(self, o = {}, locals);
12440         return o[key] = value;
12441       }
12442     });
12443   },
12444
12445   functionCall: function(fnGetter, contextGetter) {
12446     var argsFn = [];
12447     if (this.peekToken().text !== ')') {
12448       do {
12449         argsFn.push(this.expression());
12450       } while (this.expect(','));
12451     }
12452     this.consume(')');
12453
12454     var expressionText = this.text;
12455     // we can safely reuse the array across invocations
12456     var args = argsFn.length ? [] : null;
12457
12458     return function $parseFunctionCall(scope, locals) {
12459       var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
12460       var fn = fnGetter(scope, locals, context) || noop;
12461
12462       if (args) {
12463         var i = argsFn.length;
12464         while (i--) {
12465           args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
12466         }
12467       }
12468
12469       ensureSafeObject(context, expressionText);
12470       ensureSafeFunction(fn, expressionText);
12471
12472       // IE doesn't have apply for some native functions
12473       var v = fn.apply
12474             ? fn.apply(context, args)
12475             : fn(args[0], args[1], args[2], args[3], args[4]);
12476
12477       if (args) {
12478         // Free-up the memory (arguments of the last function call).
12479         args.length = 0;
12480       }
12481
12482       return ensureSafeObject(v, expressionText);
12483       };
12484   },
12485
12486   // This is used with json array declaration
12487   arrayDeclaration: function() {
12488     var elementFns = [];
12489     if (this.peekToken().text !== ']') {
12490       do {
12491         if (this.peek(']')) {
12492           // Support trailing commas per ES5.1.
12493           break;
12494         }
12495         elementFns.push(this.expression());
12496       } while (this.expect(','));
12497     }
12498     this.consume(']');
12499
12500     return extend(function $parseArrayLiteral(self, locals) {
12501       var array = [];
12502       for (var i = 0, ii = elementFns.length; i < ii; i++) {
12503         array.push(elementFns[i](self, locals));
12504       }
12505       return array;
12506     }, {
12507       literal: true,
12508       constant: elementFns.every(isConstant),
12509       inputs: elementFns
12510     });
12511   },
12512
12513   object: function() {
12514     var keys = [], valueFns = [];
12515     if (this.peekToken().text !== '}') {
12516       do {
12517         if (this.peek('}')) {
12518           // Support trailing commas per ES5.1.
12519           break;
12520         }
12521         var token = this.consume();
12522         if (token.constant) {
12523           keys.push(token.value);
12524         } else if (token.identifier) {
12525           keys.push(token.text);
12526         } else {
12527           this.throwError("invalid key", token);
12528         }
12529         this.consume(':');
12530         valueFns.push(this.expression());
12531       } while (this.expect(','));
12532     }
12533     this.consume('}');
12534
12535     return extend(function $parseObjectLiteral(self, locals) {
12536       var object = {};
12537       for (var i = 0, ii = valueFns.length; i < ii; i++) {
12538         object[keys[i]] = valueFns[i](self, locals);
12539       }
12540       return object;
12541     }, {
12542       literal: true,
12543       constant: valueFns.every(isConstant),
12544       inputs: valueFns
12545     });
12546   }
12547 };
12548
12549
12550 //////////////////////////////////////////////////
12551 // Parser helper functions
12552 //////////////////////////////////////////////////
12553
12554 function setter(obj, locals, path, setValue, fullExp) {
12555   ensureSafeObject(obj, fullExp);
12556   ensureSafeObject(locals, fullExp);
12557
12558   var element = path.split('.'), key;
12559   for (var i = 0; element.length > 1; i++) {
12560     key = ensureSafeMemberName(element.shift(), fullExp);
12561     var propertyObj = (i === 0 && locals && locals[key]) || obj[key];
12562     if (!propertyObj) {
12563       propertyObj = {};
12564       obj[key] = propertyObj;
12565     }
12566     obj = ensureSafeObject(propertyObj, fullExp);
12567   }
12568   key = ensureSafeMemberName(element.shift(), fullExp);
12569   ensureSafeObject(obj[key], fullExp);
12570   obj[key] = setValue;
12571   return setValue;
12572 }
12573
12574 var getterFnCacheDefault = createMap();
12575 var getterFnCacheExpensive = createMap();
12576
12577 function isPossiblyDangerousMemberName(name) {
12578   return name == 'constructor';
12579 }
12580
12581 /**
12582  * Implementation of the "Black Hole" variant from:
12583  * - http://jsperf.com/angularjs-parse-getter/4
12584  * - http://jsperf.com/path-evaluation-simplified/7
12585  */
12586 function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) {
12587   ensureSafeMemberName(key0, fullExp);
12588   ensureSafeMemberName(key1, fullExp);
12589   ensureSafeMemberName(key2, fullExp);
12590   ensureSafeMemberName(key3, fullExp);
12591   ensureSafeMemberName(key4, fullExp);
12592   var eso = function(o) {
12593     return ensureSafeObject(o, fullExp);
12594   };
12595   var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
12596   var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
12597   var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
12598   var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
12599   var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
12600
12601   return function cspSafeGetter(scope, locals) {
12602     var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
12603
12604     if (pathVal == null) return pathVal;
12605     pathVal = eso0(pathVal[key0]);
12606
12607     if (!key1) return pathVal;
12608     if (pathVal == null) return undefined;
12609     pathVal = eso1(pathVal[key1]);
12610
12611     if (!key2) return pathVal;
12612     if (pathVal == null) return undefined;
12613     pathVal = eso2(pathVal[key2]);
12614
12615     if (!key3) return pathVal;
12616     if (pathVal == null) return undefined;
12617     pathVal = eso3(pathVal[key3]);
12618
12619     if (!key4) return pathVal;
12620     if (pathVal == null) return undefined;
12621     pathVal = eso4(pathVal[key4]);
12622
12623     return pathVal;
12624   };
12625 }
12626
12627 function getterFnWithEnsureSafeObject(fn, fullExpression) {
12628   return function(s, l) {
12629     return fn(s, l, ensureSafeObject, fullExpression);
12630   };
12631 }
12632
12633 function getterFn(path, options, fullExp) {
12634   var expensiveChecks = options.expensiveChecks;
12635   var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
12636   var fn = getterFnCache[path];
12637   if (fn) return fn;
12638
12639
12640   var pathKeys = path.split('.'),
12641       pathKeysLength = pathKeys.length;
12642
12643   // http://jsperf.com/angularjs-parse-getter/6
12644   if (options.csp) {
12645     if (pathKeysLength < 6) {
12646       fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks);
12647     } else {
12648       fn = function cspSafeGetter(scope, locals) {
12649         var i = 0, val;
12650         do {
12651           val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
12652                                 pathKeys[i++], fullExp, expensiveChecks)(scope, locals);
12653
12654           locals = undefined; // clear after first iteration
12655           scope = val;
12656         } while (i < pathKeysLength);
12657         return val;
12658       };
12659     }
12660   } else {
12661     var code = '';
12662     if (expensiveChecks) {
12663       code += 's = eso(s, fe);\nl = eso(l, fe);\n';
12664     }
12665     var needsEnsureSafeObject = expensiveChecks;
12666     forEach(pathKeys, function(key, index) {
12667       ensureSafeMemberName(key, fullExp);
12668       var lookupJs = (index
12669                       // we simply dereference 's' on any .dot notation
12670                       ? 's'
12671                       // but if we are first then we check locals first, and if so read it first
12672                       : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key;
12673       if (expensiveChecks || isPossiblyDangerousMemberName(key)) {
12674         lookupJs = 'eso(' + lookupJs + ', fe)';
12675         needsEnsureSafeObject = true;
12676       }
12677       code += 'if(s == null) return undefined;\n' +
12678               's=' + lookupJs + ';\n';
12679     });
12680     code += 'return s;';
12681
12682     /* jshint -W054 */
12683     var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject
12684     /* jshint +W054 */
12685     evaledFnGetter.toString = valueFn(code);
12686     if (needsEnsureSafeObject) {
12687       evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp);
12688     }
12689     fn = evaledFnGetter;
12690   }
12691
12692   fn.sharedGetter = true;
12693   fn.assign = function(self, value, locals) {
12694     return setter(self, locals, path, value, path);
12695   };
12696   getterFnCache[path] = fn;
12697   return fn;
12698 }
12699
12700 var objectValueOf = Object.prototype.valueOf;
12701
12702 function getValueOf(value) {
12703   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
12704 }
12705
12706 ///////////////////////////////////
12707
12708 /**
12709  * @ngdoc service
12710  * @name $parse
12711  * @kind function
12712  *
12713  * @description
12714  *
12715  * Converts Angular {@link guide/expression expression} into a function.
12716  *
12717  * ```js
12718  *   var getter = $parse('user.name');
12719  *   var setter = getter.assign;
12720  *   var context = {user:{name:'angular'}};
12721  *   var locals = {user:{name:'local'}};
12722  *
12723  *   expect(getter(context)).toEqual('angular');
12724  *   setter(context, 'newValue');
12725  *   expect(context.user.name).toEqual('newValue');
12726  *   expect(getter(context, locals)).toEqual('local');
12727  * ```
12728  *
12729  *
12730  * @param {string} expression String expression to compile.
12731  * @returns {function(context, locals)} a function which represents the compiled expression:
12732  *
12733  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
12734  *      are evaluated against (typically a scope object).
12735  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
12736  *      `context`.
12737  *
12738  *    The returned function also has the following properties:
12739  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
12740  *        literal.
12741  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
12742  *        constant literals.
12743  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
12744  *        set to a function to change its value on the given context.
12745  *
12746  */
12747
12748
12749 /**
12750  * @ngdoc provider
12751  * @name $parseProvider
12752  *
12753  * @description
12754  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
12755  *  service.
12756  */
12757 function $ParseProvider() {
12758   var cacheDefault = createMap();
12759   var cacheExpensive = createMap();
12760
12761
12762
12763   this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
12764     var $parseOptions = {
12765           csp: $sniffer.csp,
12766           expensiveChecks: false
12767         },
12768         $parseOptionsExpensive = {
12769           csp: $sniffer.csp,
12770           expensiveChecks: true
12771         };
12772
12773     function wrapSharedExpression(exp) {
12774       var wrapped = exp;
12775
12776       if (exp.sharedGetter) {
12777         wrapped = function $parseWrapper(self, locals) {
12778           return exp(self, locals);
12779         };
12780         wrapped.literal = exp.literal;
12781         wrapped.constant = exp.constant;
12782         wrapped.assign = exp.assign;
12783       }
12784
12785       return wrapped;
12786     }
12787
12788     return function $parse(exp, interceptorFn, expensiveChecks) {
12789       var parsedExpression, oneTime, cacheKey;
12790
12791       switch (typeof exp) {
12792         case 'string':
12793           cacheKey = exp = exp.trim();
12794
12795           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
12796           parsedExpression = cache[cacheKey];
12797
12798           if (!parsedExpression) {
12799             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
12800               oneTime = true;
12801               exp = exp.substring(2);
12802             }
12803
12804             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
12805             var lexer = new Lexer(parseOptions);
12806             var parser = new Parser(lexer, $filter, parseOptions);
12807             parsedExpression = parser.parse(exp);
12808
12809             if (parsedExpression.constant) {
12810               parsedExpression.$$watchDelegate = constantWatchDelegate;
12811             } else if (oneTime) {
12812               //oneTime is not part of the exp passed to the Parser so we may have to
12813               //wrap the parsedExpression before adding a $$watchDelegate
12814               parsedExpression = wrapSharedExpression(parsedExpression);
12815               parsedExpression.$$watchDelegate = parsedExpression.literal ?
12816                 oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
12817             } else if (parsedExpression.inputs) {
12818               parsedExpression.$$watchDelegate = inputsWatchDelegate;
12819             }
12820
12821             cache[cacheKey] = parsedExpression;
12822           }
12823           return addInterceptor(parsedExpression, interceptorFn);
12824
12825         case 'function':
12826           return addInterceptor(exp, interceptorFn);
12827
12828         default:
12829           return addInterceptor(noop, interceptorFn);
12830       }
12831     };
12832
12833     function collectExpressionInputs(inputs, list) {
12834       for (var i = 0, ii = inputs.length; i < ii; i++) {
12835         var input = inputs[i];
12836         if (!input.constant) {
12837           if (input.inputs) {
12838             collectExpressionInputs(input.inputs, list);
12839           } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better?
12840             list.push(input);
12841           }
12842         }
12843       }
12844
12845       return list;
12846     }
12847
12848     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
12849
12850       if (newValue == null || oldValueOfValue == null) { // null/undefined
12851         return newValue === oldValueOfValue;
12852       }
12853
12854       if (typeof newValue === 'object') {
12855
12856         // attempt to convert the value to a primitive type
12857         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
12858         //             be cheaply dirty-checked
12859         newValue = getValueOf(newValue);
12860
12861         if (typeof newValue === 'object') {
12862           // objects/arrays are not supported - deep-watching them would be too expensive
12863           return false;
12864         }
12865
12866         // fall-through to the primitive equality check
12867       }
12868
12869       //Primitive or NaN
12870       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
12871     }
12872
12873     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12874       var inputExpressions = parsedExpression.$$inputs ||
12875                     (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, []));
12876
12877       var lastResult;
12878
12879       if (inputExpressions.length === 1) {
12880         var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails
12881         inputExpressions = inputExpressions[0];
12882         return scope.$watch(function expressionInputWatch(scope) {
12883           var newInputValue = inputExpressions(scope);
12884           if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) {
12885             lastResult = parsedExpression(scope);
12886             oldInputValue = newInputValue && getValueOf(newInputValue);
12887           }
12888           return lastResult;
12889         }, listener, objectEquality);
12890       }
12891
12892       var oldInputValueOfValues = [];
12893       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12894         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
12895       }
12896
12897       return scope.$watch(function expressionInputsWatch(scope) {
12898         var changed = false;
12899
12900         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12901           var newInputValue = inputExpressions[i](scope);
12902           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
12903             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
12904           }
12905         }
12906
12907         if (changed) {
12908           lastResult = parsedExpression(scope);
12909         }
12910
12911         return lastResult;
12912       }, listener, objectEquality);
12913     }
12914
12915     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12916       var unwatch, lastValue;
12917       return unwatch = scope.$watch(function oneTimeWatch(scope) {
12918         return parsedExpression(scope);
12919       }, function oneTimeListener(value, old, scope) {
12920         lastValue = value;
12921         if (isFunction(listener)) {
12922           listener.apply(this, arguments);
12923         }
12924         if (isDefined(value)) {
12925           scope.$$postDigest(function() {
12926             if (isDefined(lastValue)) {
12927               unwatch();
12928             }
12929           });
12930         }
12931       }, objectEquality);
12932     }
12933
12934     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12935       var unwatch, lastValue;
12936       return unwatch = scope.$watch(function oneTimeWatch(scope) {
12937         return parsedExpression(scope);
12938       }, function oneTimeListener(value, old, scope) {
12939         lastValue = value;
12940         if (isFunction(listener)) {
12941           listener.call(this, value, old, scope);
12942         }
12943         if (isAllDefined(value)) {
12944           scope.$$postDigest(function() {
12945             if (isAllDefined(lastValue)) unwatch();
12946           });
12947         }
12948       }, objectEquality);
12949
12950       function isAllDefined(value) {
12951         var allDefined = true;
12952         forEach(value, function(val) {
12953           if (!isDefined(val)) allDefined = false;
12954         });
12955         return allDefined;
12956       }
12957     }
12958
12959     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12960       var unwatch;
12961       return unwatch = scope.$watch(function constantWatch(scope) {
12962         return parsedExpression(scope);
12963       }, function constantListener(value, old, scope) {
12964         if (isFunction(listener)) {
12965           listener.apply(this, arguments);
12966         }
12967         unwatch();
12968       }, objectEquality);
12969     }
12970
12971     function addInterceptor(parsedExpression, interceptorFn) {
12972       if (!interceptorFn) return parsedExpression;
12973       var watchDelegate = parsedExpression.$$watchDelegate;
12974
12975       var regularWatch =
12976           watchDelegate !== oneTimeLiteralWatchDelegate &&
12977           watchDelegate !== oneTimeWatchDelegate;
12978
12979       var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
12980         var value = parsedExpression(scope, locals);
12981         return interceptorFn(value, scope, locals);
12982       } : function oneTimeInterceptedExpression(scope, locals) {
12983         var value = parsedExpression(scope, locals);
12984         var result = interceptorFn(value, scope, locals);
12985         // we only return the interceptor's result if the
12986         // initial value is defined (for bind-once)
12987         return isDefined(value) ? result : value;
12988       };
12989
12990       // Propagate $$watchDelegates other then inputsWatchDelegate
12991       if (parsedExpression.$$watchDelegate &&
12992           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
12993         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
12994       } else if (!interceptorFn.$stateful) {
12995         // If there is an interceptor, but no watchDelegate then treat the interceptor like
12996         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
12997         fn.$$watchDelegate = inputsWatchDelegate;
12998         fn.inputs = [parsedExpression];
12999       }
13000
13001       return fn;
13002     }
13003   }];
13004 }
13005
13006 /**
13007  * @ngdoc service
13008  * @name $q
13009  * @requires $rootScope
13010  *
13011  * @description
13012  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
13013  * when they are done processing.
13014  *
13015  * This is an implementation of promises/deferred objects inspired by
13016  * [Kris Kowal's Q](https://github.com/kriskowal/q).
13017  *
13018  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
13019  * implementations, and the other which resembles ES6 promises to some degree.
13020  *
13021  * # $q constructor
13022  *
13023  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
13024  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
13025  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
13026  *
13027  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
13028  * available yet.
13029  *
13030  * It can be used like so:
13031  *
13032  * ```js
13033  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
13034  *   // are available in the current lexical scope (they could have been injected or passed in).
13035  *
13036  *   function asyncGreet(name) {
13037  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
13038  *     return $q(function(resolve, reject) {
13039  *       setTimeout(function() {
13040  *         if (okToGreet(name)) {
13041  *           resolve('Hello, ' + name + '!');
13042  *         } else {
13043  *           reject('Greeting ' + name + ' is not allowed.');
13044  *         }
13045  *       }, 1000);
13046  *     });
13047  *   }
13048  *
13049  *   var promise = asyncGreet('Robin Hood');
13050  *   promise.then(function(greeting) {
13051  *     alert('Success: ' + greeting);
13052  *   }, function(reason) {
13053  *     alert('Failed: ' + reason);
13054  *   });
13055  * ```
13056  *
13057  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
13058  *
13059  * However, the more traditional CommonJS-style usage is still available, and documented below.
13060  *
13061  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
13062  * interface for interacting with an object that represents the result of an action that is
13063  * performed asynchronously, and may or may not be finished at any given point in time.
13064  *
13065  * From the perspective of dealing with error handling, deferred and promise APIs are to
13066  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
13067  *
13068  * ```js
13069  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
13070  *   // are available in the current lexical scope (they could have been injected or passed in).
13071  *
13072  *   function asyncGreet(name) {
13073  *     var deferred = $q.defer();
13074  *
13075  *     setTimeout(function() {
13076  *       deferred.notify('About to greet ' + name + '.');
13077  *
13078  *       if (okToGreet(name)) {
13079  *         deferred.resolve('Hello, ' + name + '!');
13080  *       } else {
13081  *         deferred.reject('Greeting ' + name + ' is not allowed.');
13082  *       }
13083  *     }, 1000);
13084  *
13085  *     return deferred.promise;
13086  *   }
13087  *
13088  *   var promise = asyncGreet('Robin Hood');
13089  *   promise.then(function(greeting) {
13090  *     alert('Success: ' + greeting);
13091  *   }, function(reason) {
13092  *     alert('Failed: ' + reason);
13093  *   }, function(update) {
13094  *     alert('Got notification: ' + update);
13095  *   });
13096  * ```
13097  *
13098  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
13099  * comes in the way of guarantees that promise and deferred APIs make, see
13100  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
13101  *
13102  * Additionally the promise api allows for composition that is very hard to do with the
13103  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
13104  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
13105  * section on serial or parallel joining of promises.
13106  *
13107  * # The Deferred API
13108  *
13109  * A new instance of deferred is constructed by calling `$q.defer()`.
13110  *
13111  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
13112  * that can be used for signaling the successful or unsuccessful completion, as well as the status
13113  * of the task.
13114  *
13115  * **Methods**
13116  *
13117  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
13118  *   constructed via `$q.reject`, the promise will be rejected instead.
13119  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
13120  *   resolving it with a rejection constructed via `$q.reject`.
13121  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
13122  *   multiple times before the promise is either resolved or rejected.
13123  *
13124  * **Properties**
13125  *
13126  * - promise – `{Promise}` – promise object associated with this deferred.
13127  *
13128  *
13129  * # The Promise API
13130  *
13131  * A new promise instance is created when a deferred instance is created and can be retrieved by
13132  * calling `deferred.promise`.
13133  *
13134  * The purpose of the promise object is to allow for interested parties to get access to the result
13135  * of the deferred task when it completes.
13136  *
13137  * **Methods**
13138  *
13139  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
13140  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
13141  *   as soon as the result is available. The callbacks are called with a single argument: the result
13142  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
13143  *   provide a progress indication, before the promise is resolved or rejected.
13144  *
13145  *   This method *returns a new promise* which is resolved or rejected via the return value of the
13146  *   `successCallback`, `errorCallback`. It also notifies via the return value of the
13147  *   `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback
13148  *   method.
13149  *
13150  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
13151  *
13152  * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
13153  *   but to do so without modifying the final value. This is useful to release resources or do some
13154  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
13155  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
13156  *   more information.
13157  *
13158  * # Chaining promises
13159  *
13160  * Because calling the `then` method of a promise returns a new derived promise, it is easily
13161  * possible to create a chain of promises:
13162  *
13163  * ```js
13164  *   promiseB = promiseA.then(function(result) {
13165  *     return result + 1;
13166  *   });
13167  *
13168  *   // promiseB will be resolved immediately after promiseA is resolved and its value
13169  *   // will be the result of promiseA incremented by 1
13170  * ```
13171  *
13172  * It is possible to create chains of any length and since a promise can be resolved with another
13173  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
13174  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
13175  * $http's response interceptors.
13176  *
13177  *
13178  * # Differences between Kris Kowal's Q and $q
13179  *
13180  *  There are two main differences:
13181  *
13182  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
13183  *   mechanism in angular, which means faster propagation of resolution or rejection into your
13184  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
13185  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
13186  *   all the important functionality needed for common async tasks.
13187  *
13188  *  # Testing
13189  *
13190  *  ```js
13191  *    it('should simulate promise', inject(function($q, $rootScope) {
13192  *      var deferred = $q.defer();
13193  *      var promise = deferred.promise;
13194  *      var resolvedValue;
13195  *
13196  *      promise.then(function(value) { resolvedValue = value; });
13197  *      expect(resolvedValue).toBeUndefined();
13198  *
13199  *      // Simulate resolving of promise
13200  *      deferred.resolve(123);
13201  *      // Note that the 'then' function does not get called synchronously.
13202  *      // This is because we want the promise API to always be async, whether or not
13203  *      // it got called synchronously or asynchronously.
13204  *      expect(resolvedValue).toBeUndefined();
13205  *
13206  *      // Propagate promise resolution to 'then' functions using $apply().
13207  *      $rootScope.$apply();
13208  *      expect(resolvedValue).toEqual(123);
13209  *    }));
13210  *  ```
13211  *
13212  * @param {function(function, function)} resolver Function which is responsible for resolving or
13213  *   rejecting the newly created promise. The first parameter is a function which resolves the
13214  *   promise, the second parameter is a function which rejects the promise.
13215  *
13216  * @returns {Promise} The newly created promise.
13217  */
13218 function $QProvider() {
13219
13220   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
13221     return qFactory(function(callback) {
13222       $rootScope.$evalAsync(callback);
13223     }, $exceptionHandler);
13224   }];
13225 }
13226
13227 function $$QProvider() {
13228   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
13229     return qFactory(function(callback) {
13230       $browser.defer(callback);
13231     }, $exceptionHandler);
13232   }];
13233 }
13234
13235 /**
13236  * Constructs a promise manager.
13237  *
13238  * @param {function(function)} nextTick Function for executing functions in the next turn.
13239  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
13240  *     debugging purposes.
13241  * @returns {object} Promise manager.
13242  */
13243 function qFactory(nextTick, exceptionHandler) {
13244   var $qMinErr = minErr('$q', TypeError);
13245   function callOnce(self, resolveFn, rejectFn) {
13246     var called = false;
13247     function wrap(fn) {
13248       return function(value) {
13249         if (called) return;
13250         called = true;
13251         fn.call(self, value);
13252       };
13253     }
13254
13255     return [wrap(resolveFn), wrap(rejectFn)];
13256   }
13257
13258   /**
13259    * @ngdoc method
13260    * @name ng.$q#defer
13261    * @kind function
13262    *
13263    * @description
13264    * Creates a `Deferred` object which represents a task which will finish in the future.
13265    *
13266    * @returns {Deferred} Returns a new instance of deferred.
13267    */
13268   var defer = function() {
13269     return new Deferred();
13270   };
13271
13272   function Promise() {
13273     this.$$state = { status: 0 };
13274   }
13275
13276   Promise.prototype = {
13277     then: function(onFulfilled, onRejected, progressBack) {
13278       var result = new Deferred();
13279
13280       this.$$state.pending = this.$$state.pending || [];
13281       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
13282       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
13283
13284       return result.promise;
13285     },
13286
13287     "catch": function(callback) {
13288       return this.then(null, callback);
13289     },
13290
13291     "finally": function(callback, progressBack) {
13292       return this.then(function(value) {
13293         return handleCallback(value, true, callback);
13294       }, function(error) {
13295         return handleCallback(error, false, callback);
13296       }, progressBack);
13297     }
13298   };
13299
13300   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
13301   function simpleBind(context, fn) {
13302     return function(value) {
13303       fn.call(context, value);
13304     };
13305   }
13306
13307   function processQueue(state) {
13308     var fn, promise, pending;
13309
13310     pending = state.pending;
13311     state.processScheduled = false;
13312     state.pending = undefined;
13313     for (var i = 0, ii = pending.length; i < ii; ++i) {
13314       promise = pending[i][0];
13315       fn = pending[i][state.status];
13316       try {
13317         if (isFunction(fn)) {
13318           promise.resolve(fn(state.value));
13319         } else if (state.status === 1) {
13320           promise.resolve(state.value);
13321         } else {
13322           promise.reject(state.value);
13323         }
13324       } catch (e) {
13325         promise.reject(e);
13326         exceptionHandler(e);
13327       }
13328     }
13329   }
13330
13331   function scheduleProcessQueue(state) {
13332     if (state.processScheduled || !state.pending) return;
13333     state.processScheduled = true;
13334     nextTick(function() { processQueue(state); });
13335   }
13336
13337   function Deferred() {
13338     this.promise = new Promise();
13339     //Necessary to support unbound execution :/
13340     this.resolve = simpleBind(this, this.resolve);
13341     this.reject = simpleBind(this, this.reject);
13342     this.notify = simpleBind(this, this.notify);
13343   }
13344
13345   Deferred.prototype = {
13346     resolve: function(val) {
13347       if (this.promise.$$state.status) return;
13348       if (val === this.promise) {
13349         this.$$reject($qMinErr(
13350           'qcycle',
13351           "Expected promise to be resolved with value other than itself '{0}'",
13352           val));
13353       } else {
13354         this.$$resolve(val);
13355       }
13356
13357     },
13358
13359     $$resolve: function(val) {
13360       var then, fns;
13361
13362       fns = callOnce(this, this.$$resolve, this.$$reject);
13363       try {
13364         if ((isObject(val) || isFunction(val))) then = val && val.then;
13365         if (isFunction(then)) {
13366           this.promise.$$state.status = -1;
13367           then.call(val, fns[0], fns[1], this.notify);
13368         } else {
13369           this.promise.$$state.value = val;
13370           this.promise.$$state.status = 1;
13371           scheduleProcessQueue(this.promise.$$state);
13372         }
13373       } catch (e) {
13374         fns[1](e);
13375         exceptionHandler(e);
13376       }
13377     },
13378
13379     reject: function(reason) {
13380       if (this.promise.$$state.status) return;
13381       this.$$reject(reason);
13382     },
13383
13384     $$reject: function(reason) {
13385       this.promise.$$state.value = reason;
13386       this.promise.$$state.status = 2;
13387       scheduleProcessQueue(this.promise.$$state);
13388     },
13389
13390     notify: function(progress) {
13391       var callbacks = this.promise.$$state.pending;
13392
13393       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
13394         nextTick(function() {
13395           var callback, result;
13396           for (var i = 0, ii = callbacks.length; i < ii; i++) {
13397             result = callbacks[i][0];
13398             callback = callbacks[i][3];
13399             try {
13400               result.notify(isFunction(callback) ? callback(progress) : progress);
13401             } catch (e) {
13402               exceptionHandler(e);
13403             }
13404           }
13405         });
13406       }
13407     }
13408   };
13409
13410   /**
13411    * @ngdoc method
13412    * @name $q#reject
13413    * @kind function
13414    *
13415    * @description
13416    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
13417    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
13418    * a promise chain, you don't need to worry about it.
13419    *
13420    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
13421    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
13422    * a promise error callback and you want to forward the error to the promise derived from the
13423    * current promise, you have to "rethrow" the error by returning a rejection constructed via
13424    * `reject`.
13425    *
13426    * ```js
13427    *   promiseB = promiseA.then(function(result) {
13428    *     // success: do something and resolve promiseB
13429    *     //          with the old or a new result
13430    *     return result;
13431    *   }, function(reason) {
13432    *     // error: handle the error if possible and
13433    *     //        resolve promiseB with newPromiseOrValue,
13434    *     //        otherwise forward the rejection to promiseB
13435    *     if (canHandle(reason)) {
13436    *      // handle the error and recover
13437    *      return newPromiseOrValue;
13438    *     }
13439    *     return $q.reject(reason);
13440    *   });
13441    * ```
13442    *
13443    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
13444    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
13445    */
13446   var reject = function(reason) {
13447     var result = new Deferred();
13448     result.reject(reason);
13449     return result.promise;
13450   };
13451
13452   var makePromise = function makePromise(value, resolved) {
13453     var result = new Deferred();
13454     if (resolved) {
13455       result.resolve(value);
13456     } else {
13457       result.reject(value);
13458     }
13459     return result.promise;
13460   };
13461
13462   var handleCallback = function handleCallback(value, isResolved, callback) {
13463     var callbackOutput = null;
13464     try {
13465       if (isFunction(callback)) callbackOutput = callback();
13466     } catch (e) {
13467       return makePromise(e, false);
13468     }
13469     if (isPromiseLike(callbackOutput)) {
13470       return callbackOutput.then(function() {
13471         return makePromise(value, isResolved);
13472       }, function(error) {
13473         return makePromise(error, false);
13474       });
13475     } else {
13476       return makePromise(value, isResolved);
13477     }
13478   };
13479
13480   /**
13481    * @ngdoc method
13482    * @name $q#when
13483    * @kind function
13484    *
13485    * @description
13486    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
13487    * This is useful when you are dealing with an object that might or might not be a promise, or if
13488    * the promise comes from a source that can't be trusted.
13489    *
13490    * @param {*} value Value or a promise
13491    * @returns {Promise} Returns a promise of the passed value or promise
13492    */
13493
13494
13495   var when = function(value, callback, errback, progressBack) {
13496     var result = new Deferred();
13497     result.resolve(value);
13498     return result.promise.then(callback, errback, progressBack);
13499   };
13500
13501   /**
13502    * @ngdoc method
13503    * @name $q#all
13504    * @kind function
13505    *
13506    * @description
13507    * Combines multiple promises into a single promise that is resolved when all of the input
13508    * promises are resolved.
13509    *
13510    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
13511    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
13512    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
13513    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
13514    *   with the same rejection value.
13515    */
13516
13517   function all(promises) {
13518     var deferred = new Deferred(),
13519         counter = 0,
13520         results = isArray(promises) ? [] : {};
13521
13522     forEach(promises, function(promise, key) {
13523       counter++;
13524       when(promise).then(function(value) {
13525         if (results.hasOwnProperty(key)) return;
13526         results[key] = value;
13527         if (!(--counter)) deferred.resolve(results);
13528       }, function(reason) {
13529         if (results.hasOwnProperty(key)) return;
13530         deferred.reject(reason);
13531       });
13532     });
13533
13534     if (counter === 0) {
13535       deferred.resolve(results);
13536     }
13537
13538     return deferred.promise;
13539   }
13540
13541   var $Q = function Q(resolver) {
13542     if (!isFunction(resolver)) {
13543       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
13544     }
13545
13546     if (!(this instanceof Q)) {
13547       // More useful when $Q is the Promise itself.
13548       return new Q(resolver);
13549     }
13550
13551     var deferred = new Deferred();
13552
13553     function resolveFn(value) {
13554       deferred.resolve(value);
13555     }
13556
13557     function rejectFn(reason) {
13558       deferred.reject(reason);
13559     }
13560
13561     resolver(resolveFn, rejectFn);
13562
13563     return deferred.promise;
13564   };
13565
13566   $Q.defer = defer;
13567   $Q.reject = reject;
13568   $Q.when = when;
13569   $Q.all = all;
13570
13571   return $Q;
13572 }
13573
13574 function $$RAFProvider() { //rAF
13575   this.$get = ['$window', '$timeout', function($window, $timeout) {
13576     var requestAnimationFrame = $window.requestAnimationFrame ||
13577                                 $window.webkitRequestAnimationFrame;
13578
13579     var cancelAnimationFrame = $window.cancelAnimationFrame ||
13580                                $window.webkitCancelAnimationFrame ||
13581                                $window.webkitCancelRequestAnimationFrame;
13582
13583     var rafSupported = !!requestAnimationFrame;
13584     var rafFn = rafSupported
13585       ? function(fn) {
13586           var id = requestAnimationFrame(fn);
13587           return function() {
13588             cancelAnimationFrame(id);
13589           };
13590         }
13591       : function(fn) {
13592           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
13593           return function() {
13594             $timeout.cancel(timer);
13595           };
13596         };
13597
13598     queueFn.supported = rafSupported;
13599
13600     var cancelLastRAF;
13601     var taskCount = 0;
13602     var taskQueue = [];
13603     return queueFn;
13604
13605     function flush() {
13606       for (var i = 0; i < taskQueue.length; i++) {
13607         var task = taskQueue[i];
13608         if (task) {
13609           taskQueue[i] = null;
13610           task();
13611         }
13612       }
13613       taskCount = taskQueue.length = 0;
13614     }
13615
13616     function queueFn(asyncFn) {
13617       var index = taskQueue.length;
13618
13619       taskCount++;
13620       taskQueue.push(asyncFn);
13621
13622       if (index === 0) {
13623         cancelLastRAF = rafFn(flush);
13624       }
13625
13626       return function cancelQueueFn() {
13627         if (index >= 0) {
13628           taskQueue[index] = null;
13629           index = null;
13630
13631           if (--taskCount === 0 && cancelLastRAF) {
13632             cancelLastRAF();
13633             cancelLastRAF = null;
13634             taskQueue.length = 0;
13635           }
13636         }
13637       };
13638     }
13639   }];
13640 }
13641
13642 /**
13643  * DESIGN NOTES
13644  *
13645  * The design decisions behind the scope are heavily favored for speed and memory consumption.
13646  *
13647  * The typical use of scope is to watch the expressions, which most of the time return the same
13648  * value as last time so we optimize the operation.
13649  *
13650  * Closures construction is expensive in terms of speed as well as memory:
13651  *   - No closures, instead use prototypical inheritance for API
13652  *   - Internal state needs to be stored on scope directly, which means that private state is
13653  *     exposed as $$____ properties
13654  *
13655  * Loop operations are optimized by using while(count--) { ... }
13656  *   - this means that in order to keep the same order of execution as addition we have to add
13657  *     items to the array at the beginning (unshift) instead of at the end (push)
13658  *
13659  * Child scopes are created and removed often
13660  *   - Using an array would be slow since inserts in middle are expensive so we use linked list
13661  *
13662  * There are few watches then a lot of observers. This is why you don't want the observer to be
13663  * implemented in the same way as watch. Watch requires return of initialization function which
13664  * are expensive to construct.
13665  */
13666
13667
13668 /**
13669  * @ngdoc provider
13670  * @name $rootScopeProvider
13671  * @description
13672  *
13673  * Provider for the $rootScope service.
13674  */
13675
13676 /**
13677  * @ngdoc method
13678  * @name $rootScopeProvider#digestTtl
13679  * @description
13680  *
13681  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
13682  * assuming that the model is unstable.
13683  *
13684  * The current default is 10 iterations.
13685  *
13686  * In complex applications it's possible that the dependencies between `$watch`s will result in
13687  * several digest iterations. However if an application needs more than the default 10 digest
13688  * iterations for its model to stabilize then you should investigate what is causing the model to
13689  * continuously change during the digest.
13690  *
13691  * Increasing the TTL could have performance implications, so you should not change it without
13692  * proper justification.
13693  *
13694  * @param {number} limit The number of digest iterations.
13695  */
13696
13697
13698 /**
13699  * @ngdoc service
13700  * @name $rootScope
13701  * @description
13702  *
13703  * Every application has a single root {@link ng.$rootScope.Scope scope}.
13704  * All other scopes are descendant scopes of the root scope. Scopes provide separation
13705  * between the model and the view, via a mechanism for watching the model for changes.
13706  * They also provide an event emission/broadcast and subscription facility. See the
13707  * {@link guide/scope developer guide on scopes}.
13708  */
13709 function $RootScopeProvider() {
13710   var TTL = 10;
13711   var $rootScopeMinErr = minErr('$rootScope');
13712   var lastDirtyWatch = null;
13713   var applyAsyncId = null;
13714
13715   this.digestTtl = function(value) {
13716     if (arguments.length) {
13717       TTL = value;
13718     }
13719     return TTL;
13720   };
13721
13722   function createChildScopeClass(parent) {
13723     function ChildScope() {
13724       this.$$watchers = this.$$nextSibling =
13725           this.$$childHead = this.$$childTail = null;
13726       this.$$listeners = {};
13727       this.$$listenerCount = {};
13728       this.$id = nextUid();
13729       this.$$ChildScope = null;
13730     }
13731     ChildScope.prototype = parent;
13732     return ChildScope;
13733   }
13734
13735   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
13736       function($injector, $exceptionHandler, $parse, $browser) {
13737
13738     function destroyChildScope($event) {
13739         $event.currentScope.$$destroyed = true;
13740     }
13741
13742     /**
13743      * @ngdoc type
13744      * @name $rootScope.Scope
13745      *
13746      * @description
13747      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
13748      * {@link auto.$injector $injector}. Child scopes are created using the
13749      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
13750      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
13751      * an in-depth introduction and usage examples.
13752      *
13753      *
13754      * # Inheritance
13755      * A scope can inherit from a parent scope, as in this example:
13756      * ```js
13757          var parent = $rootScope;
13758          var child = parent.$new();
13759
13760          parent.salutation = "Hello";
13761          expect(child.salutation).toEqual('Hello');
13762
13763          child.salutation = "Welcome";
13764          expect(child.salutation).toEqual('Welcome');
13765          expect(parent.salutation).toEqual('Hello');
13766      * ```
13767      *
13768      * When interacting with `Scope` in tests, additional helper methods are available on the
13769      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
13770      * details.
13771      *
13772      *
13773      * @param {Object.<string, function()>=} providers Map of service factory which need to be
13774      *                                       provided for the current scope. Defaults to {@link ng}.
13775      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
13776      *                              append/override services provided by `providers`. This is handy
13777      *                              when unit-testing and having the need to override a default
13778      *                              service.
13779      * @returns {Object} Newly created scope.
13780      *
13781      */
13782     function Scope() {
13783       this.$id = nextUid();
13784       this.$$phase = this.$parent = this.$$watchers =
13785                      this.$$nextSibling = this.$$prevSibling =
13786                      this.$$childHead = this.$$childTail = null;
13787       this.$root = this;
13788       this.$$destroyed = false;
13789       this.$$listeners = {};
13790       this.$$listenerCount = {};
13791       this.$$isolateBindings = null;
13792     }
13793
13794     /**
13795      * @ngdoc property
13796      * @name $rootScope.Scope#$id
13797      *
13798      * @description
13799      * Unique scope ID (monotonically increasing) useful for debugging.
13800      */
13801
13802      /**
13803       * @ngdoc property
13804       * @name $rootScope.Scope#$parent
13805       *
13806       * @description
13807       * Reference to the parent scope.
13808       */
13809
13810       /**
13811        * @ngdoc property
13812        * @name $rootScope.Scope#$root
13813        *
13814        * @description
13815        * Reference to the root scope.
13816        */
13817
13818     Scope.prototype = {
13819       constructor: Scope,
13820       /**
13821        * @ngdoc method
13822        * @name $rootScope.Scope#$new
13823        * @kind function
13824        *
13825        * @description
13826        * Creates a new child {@link ng.$rootScope.Scope scope}.
13827        *
13828        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
13829        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
13830        *
13831        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
13832        * desired for the scope and its child scopes to be permanently detached from the parent and
13833        * thus stop participating in model change detection and listener notification by invoking.
13834        *
13835        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
13836        *         parent scope. The scope is isolated, as it can not see parent scope properties.
13837        *         When creating widgets, it is useful for the widget to not accidentally read parent
13838        *         state.
13839        *
13840        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
13841        *                              of the newly created scope. Defaults to `this` scope if not provided.
13842        *                              This is used when creating a transclude scope to correctly place it
13843        *                              in the scope hierarchy while maintaining the correct prototypical
13844        *                              inheritance.
13845        *
13846        * @returns {Object} The newly created child scope.
13847        *
13848        */
13849       $new: function(isolate, parent) {
13850         var child;
13851
13852         parent = parent || this;
13853
13854         if (isolate) {
13855           child = new Scope();
13856           child.$root = this.$root;
13857         } else {
13858           // Only create a child scope class if somebody asks for one,
13859           // but cache it to allow the VM to optimize lookups.
13860           if (!this.$$ChildScope) {
13861             this.$$ChildScope = createChildScopeClass(this);
13862           }
13863           child = new this.$$ChildScope();
13864         }
13865         child.$parent = parent;
13866         child.$$prevSibling = parent.$$childTail;
13867         if (parent.$$childHead) {
13868           parent.$$childTail.$$nextSibling = child;
13869           parent.$$childTail = child;
13870         } else {
13871           parent.$$childHead = parent.$$childTail = child;
13872         }
13873
13874         // When the new scope is not isolated or we inherit from `this`, and
13875         // the parent scope is destroyed, the property `$$destroyed` is inherited
13876         // prototypically. In all other cases, this property needs to be set
13877         // when the parent scope is destroyed.
13878         // The listener needs to be added after the parent is set
13879         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
13880
13881         return child;
13882       },
13883
13884       /**
13885        * @ngdoc method
13886        * @name $rootScope.Scope#$watch
13887        * @kind function
13888        *
13889        * @description
13890        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
13891        *
13892        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
13893        *   $digest()} and should return the value that will be watched. (Since
13894        *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
13895        *   `watchExpression` can execute multiple times per
13896        *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
13897        * - The `listener` is called only when the value from the current `watchExpression` and the
13898        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
13899        *   see below). Inequality is determined according to reference inequality,
13900        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
13901        *    via the `!==` Javascript operator, unless `objectEquality == true`
13902        *   (see next point)
13903        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
13904        *   according to the {@link angular.equals} function. To save the value of the object for
13905        *   later comparison, the {@link angular.copy} function is used. This therefore means that
13906        *   watching complex objects will have adverse memory and performance implications.
13907        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
13908        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
13909        *   iteration limit is 10 to prevent an infinite loop deadlock.
13910        *
13911        *
13912        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
13913        * you can register a `watchExpression` function with no `listener`. (Be prepared for
13914        * multiple calls to your `watchExpression` because it will execute multiple times in a
13915        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
13916        *
13917        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
13918        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
13919        * watcher. In rare cases, this is undesirable because the listener is called when the result
13920        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
13921        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
13922        * listener was called due to initialization.
13923        *
13924        *
13925        *
13926        * # Example
13927        * ```js
13928            // let's assume that scope was dependency injected as the $rootScope
13929            var scope = $rootScope;
13930            scope.name = 'misko';
13931            scope.counter = 0;
13932
13933            expect(scope.counter).toEqual(0);
13934            scope.$watch('name', function(newValue, oldValue) {
13935              scope.counter = scope.counter + 1;
13936            });
13937            expect(scope.counter).toEqual(0);
13938
13939            scope.$digest();
13940            // the listener is always called during the first $digest loop after it was registered
13941            expect(scope.counter).toEqual(1);
13942
13943            scope.$digest();
13944            // but now it will not be called unless the value changes
13945            expect(scope.counter).toEqual(1);
13946
13947            scope.name = 'adam';
13948            scope.$digest();
13949            expect(scope.counter).toEqual(2);
13950
13951
13952
13953            // Using a function as a watchExpression
13954            var food;
13955            scope.foodCounter = 0;
13956            expect(scope.foodCounter).toEqual(0);
13957            scope.$watch(
13958              // This function returns the value being watched. It is called for each turn of the $digest loop
13959              function() { return food; },
13960              // This is the change listener, called when the value returned from the above function changes
13961              function(newValue, oldValue) {
13962                if ( newValue !== oldValue ) {
13963                  // Only increment the counter if the value changed
13964                  scope.foodCounter = scope.foodCounter + 1;
13965                }
13966              }
13967            );
13968            // No digest has been run so the counter will be zero
13969            expect(scope.foodCounter).toEqual(0);
13970
13971            // Run the digest but since food has not changed count will still be zero
13972            scope.$digest();
13973            expect(scope.foodCounter).toEqual(0);
13974
13975            // Update food and run digest.  Now the counter will increment
13976            food = 'cheeseburger';
13977            scope.$digest();
13978            expect(scope.foodCounter).toEqual(1);
13979
13980        * ```
13981        *
13982        *
13983        *
13984        * @param {(function()|string)} watchExpression Expression that is evaluated on each
13985        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
13986        *    a call to the `listener`.
13987        *
13988        *    - `string`: Evaluated as {@link guide/expression expression}
13989        *    - `function(scope)`: called with current `scope` as a parameter.
13990        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
13991        *    of `watchExpression` changes.
13992        *
13993        *    - `newVal` contains the current value of the `watchExpression`
13994        *    - `oldVal` contains the previous value of the `watchExpression`
13995        *    - `scope` refers to the current scope
13996        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
13997        *     comparing for reference equality.
13998        * @returns {function()} Returns a deregistration function for this listener.
13999        */
14000       $watch: function(watchExp, listener, objectEquality) {
14001         var get = $parse(watchExp);
14002
14003         if (get.$$watchDelegate) {
14004           return get.$$watchDelegate(this, listener, objectEquality, get);
14005         }
14006         var scope = this,
14007             array = scope.$$watchers,
14008             watcher = {
14009               fn: listener,
14010               last: initWatchVal,
14011               get: get,
14012               exp: watchExp,
14013               eq: !!objectEquality
14014             };
14015
14016         lastDirtyWatch = null;
14017
14018         if (!isFunction(listener)) {
14019           watcher.fn = noop;
14020         }
14021
14022         if (!array) {
14023           array = scope.$$watchers = [];
14024         }
14025         // we use unshift since we use a while loop in $digest for speed.
14026         // the while loop reads in reverse order.
14027         array.unshift(watcher);
14028
14029         return function deregisterWatch() {
14030           arrayRemove(array, watcher);
14031           lastDirtyWatch = null;
14032         };
14033       },
14034
14035       /**
14036        * @ngdoc method
14037        * @name $rootScope.Scope#$watchGroup
14038        * @kind function
14039        *
14040        * @description
14041        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
14042        * If any one expression in the collection changes the `listener` is executed.
14043        *
14044        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
14045        *   call to $digest() to see if any items changes.
14046        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
14047        *
14048        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
14049        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
14050        *
14051        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
14052        *    expression in `watchExpressions` changes
14053        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
14054        *    those of `watchExpression`
14055        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
14056        *    those of `watchExpression`
14057        *    The `scope` refers to the current scope.
14058        * @returns {function()} Returns a de-registration function for all listeners.
14059        */
14060       $watchGroup: function(watchExpressions, listener) {
14061         var oldValues = new Array(watchExpressions.length);
14062         var newValues = new Array(watchExpressions.length);
14063         var deregisterFns = [];
14064         var self = this;
14065         var changeReactionScheduled = false;
14066         var firstRun = true;
14067
14068         if (!watchExpressions.length) {
14069           // No expressions means we call the listener ASAP
14070           var shouldCall = true;
14071           self.$evalAsync(function() {
14072             if (shouldCall) listener(newValues, newValues, self);
14073           });
14074           return function deregisterWatchGroup() {
14075             shouldCall = false;
14076           };
14077         }
14078
14079         if (watchExpressions.length === 1) {
14080           // Special case size of one
14081           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
14082             newValues[0] = value;
14083             oldValues[0] = oldValue;
14084             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
14085           });
14086         }
14087
14088         forEach(watchExpressions, function(expr, i) {
14089           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
14090             newValues[i] = value;
14091             oldValues[i] = oldValue;
14092             if (!changeReactionScheduled) {
14093               changeReactionScheduled = true;
14094               self.$evalAsync(watchGroupAction);
14095             }
14096           });
14097           deregisterFns.push(unwatchFn);
14098         });
14099
14100         function watchGroupAction() {
14101           changeReactionScheduled = false;
14102
14103           if (firstRun) {
14104             firstRun = false;
14105             listener(newValues, newValues, self);
14106           } else {
14107             listener(newValues, oldValues, self);
14108           }
14109         }
14110
14111         return function deregisterWatchGroup() {
14112           while (deregisterFns.length) {
14113             deregisterFns.shift()();
14114           }
14115         };
14116       },
14117
14118
14119       /**
14120        * @ngdoc method
14121        * @name $rootScope.Scope#$watchCollection
14122        * @kind function
14123        *
14124        * @description
14125        * Shallow watches the properties of an object and fires whenever any of the properties change
14126        * (for arrays, this implies watching the array items; for object maps, this implies watching
14127        * the properties). If a change is detected, the `listener` callback is fired.
14128        *
14129        * - The `obj` collection is observed via standard $watch operation and is examined on every
14130        *   call to $digest() to see if any items have been added, removed, or moved.
14131        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
14132        *   adding, removing, and moving items belonging to an object or array.
14133        *
14134        *
14135        * # Example
14136        * ```js
14137           $scope.names = ['igor', 'matias', 'misko', 'james'];
14138           $scope.dataCount = 4;
14139
14140           $scope.$watchCollection('names', function(newNames, oldNames) {
14141             $scope.dataCount = newNames.length;
14142           });
14143
14144           expect($scope.dataCount).toEqual(4);
14145           $scope.$digest();
14146
14147           //still at 4 ... no changes
14148           expect($scope.dataCount).toEqual(4);
14149
14150           $scope.names.pop();
14151           $scope.$digest();
14152
14153           //now there's been a change
14154           expect($scope.dataCount).toEqual(3);
14155        * ```
14156        *
14157        *
14158        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
14159        *    expression value should evaluate to an object or an array which is observed on each
14160        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
14161        *    collection will trigger a call to the `listener`.
14162        *
14163        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
14164        *    when a change is detected.
14165        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
14166        *    - The `oldCollection` object is a copy of the former collection data.
14167        *      Due to performance considerations, the`oldCollection` value is computed only if the
14168        *      `listener` function declares two or more arguments.
14169        *    - The `scope` argument refers to the current scope.
14170        *
14171        * @returns {function()} Returns a de-registration function for this listener. When the
14172        *    de-registration function is executed, the internal watch operation is terminated.
14173        */
14174       $watchCollection: function(obj, listener) {
14175         $watchCollectionInterceptor.$stateful = true;
14176
14177         var self = this;
14178         // the current value, updated on each dirty-check run
14179         var newValue;
14180         // a shallow copy of the newValue from the last dirty-check run,
14181         // updated to match newValue during dirty-check run
14182         var oldValue;
14183         // a shallow copy of the newValue from when the last change happened
14184         var veryOldValue;
14185         // only track veryOldValue if the listener is asking for it
14186         var trackVeryOldValue = (listener.length > 1);
14187         var changeDetected = 0;
14188         var changeDetector = $parse(obj, $watchCollectionInterceptor);
14189         var internalArray = [];
14190         var internalObject = {};
14191         var initRun = true;
14192         var oldLength = 0;
14193
14194         function $watchCollectionInterceptor(_value) {
14195           newValue = _value;
14196           var newLength, key, bothNaN, newItem, oldItem;
14197
14198           // If the new value is undefined, then return undefined as the watch may be a one-time watch
14199           if (isUndefined(newValue)) return;
14200
14201           if (!isObject(newValue)) { // if primitive
14202             if (oldValue !== newValue) {
14203               oldValue = newValue;
14204               changeDetected++;
14205             }
14206           } else if (isArrayLike(newValue)) {
14207             if (oldValue !== internalArray) {
14208               // we are transitioning from something which was not an array into array.
14209               oldValue = internalArray;
14210               oldLength = oldValue.length = 0;
14211               changeDetected++;
14212             }
14213
14214             newLength = newValue.length;
14215
14216             if (oldLength !== newLength) {
14217               // if lengths do not match we need to trigger change notification
14218               changeDetected++;
14219               oldValue.length = oldLength = newLength;
14220             }
14221             // copy the items to oldValue and look for changes.
14222             for (var i = 0; i < newLength; i++) {
14223               oldItem = oldValue[i];
14224               newItem = newValue[i];
14225
14226               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14227               if (!bothNaN && (oldItem !== newItem)) {
14228                 changeDetected++;
14229                 oldValue[i] = newItem;
14230               }
14231             }
14232           } else {
14233             if (oldValue !== internalObject) {
14234               // we are transitioning from something which was not an object into object.
14235               oldValue = internalObject = {};
14236               oldLength = 0;
14237               changeDetected++;
14238             }
14239             // copy the items to oldValue and look for changes.
14240             newLength = 0;
14241             for (key in newValue) {
14242               if (newValue.hasOwnProperty(key)) {
14243                 newLength++;
14244                 newItem = newValue[key];
14245                 oldItem = oldValue[key];
14246
14247                 if (key in oldValue) {
14248                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14249                   if (!bothNaN && (oldItem !== newItem)) {
14250                     changeDetected++;
14251                     oldValue[key] = newItem;
14252                   }
14253                 } else {
14254                   oldLength++;
14255                   oldValue[key] = newItem;
14256                   changeDetected++;
14257                 }
14258               }
14259             }
14260             if (oldLength > newLength) {
14261               // we used to have more keys, need to find them and destroy them.
14262               changeDetected++;
14263               for (key in oldValue) {
14264                 if (!newValue.hasOwnProperty(key)) {
14265                   oldLength--;
14266                   delete oldValue[key];
14267                 }
14268               }
14269             }
14270           }
14271           return changeDetected;
14272         }
14273
14274         function $watchCollectionAction() {
14275           if (initRun) {
14276             initRun = false;
14277             listener(newValue, newValue, self);
14278           } else {
14279             listener(newValue, veryOldValue, self);
14280           }
14281
14282           // make a copy for the next time a collection is changed
14283           if (trackVeryOldValue) {
14284             if (!isObject(newValue)) {
14285               //primitive
14286               veryOldValue = newValue;
14287             } else if (isArrayLike(newValue)) {
14288               veryOldValue = new Array(newValue.length);
14289               for (var i = 0; i < newValue.length; i++) {
14290                 veryOldValue[i] = newValue[i];
14291               }
14292             } else { // if object
14293               veryOldValue = {};
14294               for (var key in newValue) {
14295                 if (hasOwnProperty.call(newValue, key)) {
14296                   veryOldValue[key] = newValue[key];
14297                 }
14298               }
14299             }
14300           }
14301         }
14302
14303         return this.$watch(changeDetector, $watchCollectionAction);
14304       },
14305
14306       /**
14307        * @ngdoc method
14308        * @name $rootScope.Scope#$digest
14309        * @kind function
14310        *
14311        * @description
14312        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
14313        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
14314        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
14315        * until no more listeners are firing. This means that it is possible to get into an infinite
14316        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
14317        * iterations exceeds 10.
14318        *
14319        * Usually, you don't call `$digest()` directly in
14320        * {@link ng.directive:ngController controllers} or in
14321        * {@link ng.$compileProvider#directive directives}.
14322        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
14323        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
14324        *
14325        * If you want to be notified whenever `$digest()` is called,
14326        * you can register a `watchExpression` function with
14327        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
14328        *
14329        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
14330        *
14331        * # Example
14332        * ```js
14333            var scope = ...;
14334            scope.name = 'misko';
14335            scope.counter = 0;
14336
14337            expect(scope.counter).toEqual(0);
14338            scope.$watch('name', function(newValue, oldValue) {
14339              scope.counter = scope.counter + 1;
14340            });
14341            expect(scope.counter).toEqual(0);
14342
14343            scope.$digest();
14344            // the listener is always called during the first $digest loop after it was registered
14345            expect(scope.counter).toEqual(1);
14346
14347            scope.$digest();
14348            // but now it will not be called unless the value changes
14349            expect(scope.counter).toEqual(1);
14350
14351            scope.name = 'adam';
14352            scope.$digest();
14353            expect(scope.counter).toEqual(2);
14354        * ```
14355        *
14356        */
14357       $digest: function() {
14358         var watch, value, last,
14359             watchers,
14360             length,
14361             dirty, ttl = TTL,
14362             next, current, target = this,
14363             watchLog = [],
14364             logIdx, logMsg, asyncTask;
14365
14366         beginPhase('$digest');
14367         // Check for changes to browser url that happened in sync before the call to $digest
14368         $browser.$$checkUrlChange();
14369
14370         if (this === $rootScope && applyAsyncId !== null) {
14371           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
14372           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
14373           $browser.defer.cancel(applyAsyncId);
14374           flushApplyAsync();
14375         }
14376
14377         lastDirtyWatch = null;
14378
14379         do { // "while dirty" loop
14380           dirty = false;
14381           current = target;
14382
14383           while (asyncQueue.length) {
14384             try {
14385               asyncTask = asyncQueue.shift();
14386               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
14387             } catch (e) {
14388               $exceptionHandler(e);
14389             }
14390             lastDirtyWatch = null;
14391           }
14392
14393           traverseScopesLoop:
14394           do { // "traverse the scopes" loop
14395             if ((watchers = current.$$watchers)) {
14396               // process our watches
14397               length = watchers.length;
14398               while (length--) {
14399                 try {
14400                   watch = watchers[length];
14401                   // Most common watches are on primitives, in which case we can short
14402                   // circuit it with === operator, only when === fails do we use .equals
14403                   if (watch) {
14404                     if ((value = watch.get(current)) !== (last = watch.last) &&
14405                         !(watch.eq
14406                             ? equals(value, last)
14407                             : (typeof value === 'number' && typeof last === 'number'
14408                                && isNaN(value) && isNaN(last)))) {
14409                       dirty = true;
14410                       lastDirtyWatch = watch;
14411                       watch.last = watch.eq ? copy(value, null) : value;
14412                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
14413                       if (ttl < 5) {
14414                         logIdx = 4 - ttl;
14415                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
14416                         watchLog[logIdx].push({
14417                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
14418                           newVal: value,
14419                           oldVal: last
14420                         });
14421                       }
14422                     } else if (watch === lastDirtyWatch) {
14423                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
14424                       // have already been tested.
14425                       dirty = false;
14426                       break traverseScopesLoop;
14427                     }
14428                   }
14429                 } catch (e) {
14430                   $exceptionHandler(e);
14431                 }
14432               }
14433             }
14434
14435             // Insanity Warning: scope depth-first traversal
14436             // yes, this code is a bit crazy, but it works and we have tests to prove it!
14437             // this piece should be kept in sync with the traversal in $broadcast
14438             if (!(next = (current.$$childHead ||
14439                 (current !== target && current.$$nextSibling)))) {
14440               while (current !== target && !(next = current.$$nextSibling)) {
14441                 current = current.$parent;
14442               }
14443             }
14444           } while ((current = next));
14445
14446           // `break traverseScopesLoop;` takes us to here
14447
14448           if ((dirty || asyncQueue.length) && !(ttl--)) {
14449             clearPhase();
14450             throw $rootScopeMinErr('infdig',
14451                 '{0} $digest() iterations reached. Aborting!\n' +
14452                 'Watchers fired in the last 5 iterations: {1}',
14453                 TTL, watchLog);
14454           }
14455
14456         } while (dirty || asyncQueue.length);
14457
14458         clearPhase();
14459
14460         while (postDigestQueue.length) {
14461           try {
14462             postDigestQueue.shift()();
14463           } catch (e) {
14464             $exceptionHandler(e);
14465           }
14466         }
14467       },
14468
14469
14470       /**
14471        * @ngdoc event
14472        * @name $rootScope.Scope#$destroy
14473        * @eventType broadcast on scope being destroyed
14474        *
14475        * @description
14476        * Broadcasted when a scope and its children are being destroyed.
14477        *
14478        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14479        * clean up DOM bindings before an element is removed from the DOM.
14480        */
14481
14482       /**
14483        * @ngdoc method
14484        * @name $rootScope.Scope#$destroy
14485        * @kind function
14486        *
14487        * @description
14488        * Removes the current scope (and all of its children) from the parent scope. Removal implies
14489        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
14490        * propagate to the current scope and its children. Removal also implies that the current
14491        * scope is eligible for garbage collection.
14492        *
14493        * The `$destroy()` is usually used by directives such as
14494        * {@link ng.directive:ngRepeat ngRepeat} for managing the
14495        * unrolling of the loop.
14496        *
14497        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
14498        * Application code can register a `$destroy` event handler that will give it a chance to
14499        * perform any necessary cleanup.
14500        *
14501        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14502        * clean up DOM bindings before an element is removed from the DOM.
14503        */
14504       $destroy: function() {
14505         // we can't destroy the root scope or a scope that has been already destroyed
14506         if (this.$$destroyed) return;
14507         var parent = this.$parent;
14508
14509         this.$broadcast('$destroy');
14510         this.$$destroyed = true;
14511         if (this === $rootScope) return;
14512
14513         for (var eventName in this.$$listenerCount) {
14514           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
14515         }
14516
14517         // sever all the references to parent scopes (after this cleanup, the current scope should
14518         // not be retained by any of our references and should be eligible for garbage collection)
14519         if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
14520         if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
14521         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
14522         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
14523
14524         // Disable listeners, watchers and apply/digest methods
14525         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
14526         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
14527         this.$$listeners = {};
14528
14529         // All of the code below is bogus code that works around V8's memory leak via optimized code
14530         // and inline caches.
14531         //
14532         // see:
14533         // - https://code.google.com/p/v8/issues/detail?id=2073#c26
14534         // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
14535         // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
14536
14537         this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
14538             this.$$childTail = this.$root = this.$$watchers = null;
14539       },
14540
14541       /**
14542        * @ngdoc method
14543        * @name $rootScope.Scope#$eval
14544        * @kind function
14545        *
14546        * @description
14547        * Executes the `expression` on the current scope and returns the result. Any exceptions in
14548        * the expression are propagated (uncaught). This is useful when evaluating Angular
14549        * expressions.
14550        *
14551        * # Example
14552        * ```js
14553            var scope = ng.$rootScope.Scope();
14554            scope.a = 1;
14555            scope.b = 2;
14556
14557            expect(scope.$eval('a+b')).toEqual(3);
14558            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
14559        * ```
14560        *
14561        * @param {(string|function())=} expression An angular expression to be executed.
14562        *
14563        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
14564        *    - `function(scope)`: execute the function with the current `scope` parameter.
14565        *
14566        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14567        * @returns {*} The result of evaluating the expression.
14568        */
14569       $eval: function(expr, locals) {
14570         return $parse(expr)(this, locals);
14571       },
14572
14573       /**
14574        * @ngdoc method
14575        * @name $rootScope.Scope#$evalAsync
14576        * @kind function
14577        *
14578        * @description
14579        * Executes the expression on the current scope at a later point in time.
14580        *
14581        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
14582        * that:
14583        *
14584        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
14585        *     rendering).
14586        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
14587        *     `expression` execution.
14588        *
14589        * Any exceptions from the execution of the expression are forwarded to the
14590        * {@link ng.$exceptionHandler $exceptionHandler} service.
14591        *
14592        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
14593        * will be scheduled. However, it is encouraged to always call code that changes the model
14594        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
14595        *
14596        * @param {(string|function())=} expression An angular expression to be executed.
14597        *
14598        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14599        *    - `function(scope)`: execute the function with the current `scope` parameter.
14600        *
14601        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14602        */
14603       $evalAsync: function(expr, locals) {
14604         // if we are outside of an $digest loop and this is the first time we are scheduling async
14605         // task also schedule async auto-flush
14606         if (!$rootScope.$$phase && !asyncQueue.length) {
14607           $browser.defer(function() {
14608             if (asyncQueue.length) {
14609               $rootScope.$digest();
14610             }
14611           });
14612         }
14613
14614         asyncQueue.push({scope: this, expression: expr, locals: locals});
14615       },
14616
14617       $$postDigest: function(fn) {
14618         postDigestQueue.push(fn);
14619       },
14620
14621       /**
14622        * @ngdoc method
14623        * @name $rootScope.Scope#$apply
14624        * @kind function
14625        *
14626        * @description
14627        * `$apply()` is used to execute an expression in angular from outside of the angular
14628        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
14629        * Because we are calling into the angular framework we need to perform proper scope life
14630        * cycle of {@link ng.$exceptionHandler exception handling},
14631        * {@link ng.$rootScope.Scope#$digest executing watches}.
14632        *
14633        * ## Life cycle
14634        *
14635        * # Pseudo-Code of `$apply()`
14636        * ```js
14637            function $apply(expr) {
14638              try {
14639                return $eval(expr);
14640              } catch (e) {
14641                $exceptionHandler(e);
14642              } finally {
14643                $root.$digest();
14644              }
14645            }
14646        * ```
14647        *
14648        *
14649        * Scope's `$apply()` method transitions through the following stages:
14650        *
14651        * 1. The {@link guide/expression expression} is executed using the
14652        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
14653        * 2. Any exceptions from the execution of the expression are forwarded to the
14654        *    {@link ng.$exceptionHandler $exceptionHandler} service.
14655        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
14656        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
14657        *
14658        *
14659        * @param {(string|function())=} exp An angular expression to be executed.
14660        *
14661        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14662        *    - `function(scope)`: execute the function with current `scope` parameter.
14663        *
14664        * @returns {*} The result of evaluating the expression.
14665        */
14666       $apply: function(expr) {
14667         try {
14668           beginPhase('$apply');
14669           return this.$eval(expr);
14670         } catch (e) {
14671           $exceptionHandler(e);
14672         } finally {
14673           clearPhase();
14674           try {
14675             $rootScope.$digest();
14676           } catch (e) {
14677             $exceptionHandler(e);
14678             throw e;
14679           }
14680         }
14681       },
14682
14683       /**
14684        * @ngdoc method
14685        * @name $rootScope.Scope#$applyAsync
14686        * @kind function
14687        *
14688        * @description
14689        * Schedule the invocation of $apply to occur at a later time. The actual time difference
14690        * varies across browsers, but is typically around ~10 milliseconds.
14691        *
14692        * This can be used to queue up multiple expressions which need to be evaluated in the same
14693        * digest.
14694        *
14695        * @param {(string|function())=} exp An angular expression to be executed.
14696        *
14697        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14698        *    - `function(scope)`: execute the function with current `scope` parameter.
14699        */
14700       $applyAsync: function(expr) {
14701         var scope = this;
14702         expr && applyAsyncQueue.push($applyAsyncExpression);
14703         scheduleApplyAsync();
14704
14705         function $applyAsyncExpression() {
14706           scope.$eval(expr);
14707         }
14708       },
14709
14710       /**
14711        * @ngdoc method
14712        * @name $rootScope.Scope#$on
14713        * @kind function
14714        *
14715        * @description
14716        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
14717        * discussion of event life cycle.
14718        *
14719        * The event listener function format is: `function(event, args...)`. The `event` object
14720        * passed into the listener has the following attributes:
14721        *
14722        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
14723        *     `$broadcast`-ed.
14724        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
14725        *     event propagates through the scope hierarchy, this property is set to null.
14726        *   - `name` - `{string}`: name of the event.
14727        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
14728        *     further event propagation (available only for events that were `$emit`-ed).
14729        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
14730        *     to true.
14731        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
14732        *
14733        * @param {string} name Event name to listen on.
14734        * @param {function(event, ...args)} listener Function to call when the event is emitted.
14735        * @returns {function()} Returns a deregistration function for this listener.
14736        */
14737       $on: function(name, listener) {
14738         var namedListeners = this.$$listeners[name];
14739         if (!namedListeners) {
14740           this.$$listeners[name] = namedListeners = [];
14741         }
14742         namedListeners.push(listener);
14743
14744         var current = this;
14745         do {
14746           if (!current.$$listenerCount[name]) {
14747             current.$$listenerCount[name] = 0;
14748           }
14749           current.$$listenerCount[name]++;
14750         } while ((current = current.$parent));
14751
14752         var self = this;
14753         return function() {
14754           var indexOfListener = namedListeners.indexOf(listener);
14755           if (indexOfListener !== -1) {
14756             namedListeners[indexOfListener] = null;
14757             decrementListenerCount(self, 1, name);
14758           }
14759         };
14760       },
14761
14762
14763       /**
14764        * @ngdoc method
14765        * @name $rootScope.Scope#$emit
14766        * @kind function
14767        *
14768        * @description
14769        * Dispatches an event `name` upwards through the scope hierarchy notifying the
14770        * registered {@link ng.$rootScope.Scope#$on} listeners.
14771        *
14772        * The event life cycle starts at the scope on which `$emit` was called. All
14773        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14774        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
14775        * registered listeners along the way. The event will stop propagating if one of the listeners
14776        * cancels it.
14777        *
14778        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14779        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14780        *
14781        * @param {string} name Event name to emit.
14782        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14783        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
14784        */
14785       $emit: function(name, args) {
14786         var empty = [],
14787             namedListeners,
14788             scope = this,
14789             stopPropagation = false,
14790             event = {
14791               name: name,
14792               targetScope: scope,
14793               stopPropagation: function() {stopPropagation = true;},
14794               preventDefault: function() {
14795                 event.defaultPrevented = true;
14796               },
14797               defaultPrevented: false
14798             },
14799             listenerArgs = concat([event], arguments, 1),
14800             i, length;
14801
14802         do {
14803           namedListeners = scope.$$listeners[name] || empty;
14804           event.currentScope = scope;
14805           for (i = 0, length = namedListeners.length; i < length; i++) {
14806
14807             // if listeners were deregistered, defragment the array
14808             if (!namedListeners[i]) {
14809               namedListeners.splice(i, 1);
14810               i--;
14811               length--;
14812               continue;
14813             }
14814             try {
14815               //allow all listeners attached to the current scope to run
14816               namedListeners[i].apply(null, listenerArgs);
14817             } catch (e) {
14818               $exceptionHandler(e);
14819             }
14820           }
14821           //if any listener on the current scope stops propagation, prevent bubbling
14822           if (stopPropagation) {
14823             event.currentScope = null;
14824             return event;
14825           }
14826           //traverse upwards
14827           scope = scope.$parent;
14828         } while (scope);
14829
14830         event.currentScope = null;
14831
14832         return event;
14833       },
14834
14835
14836       /**
14837        * @ngdoc method
14838        * @name $rootScope.Scope#$broadcast
14839        * @kind function
14840        *
14841        * @description
14842        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
14843        * registered {@link ng.$rootScope.Scope#$on} listeners.
14844        *
14845        * The event life cycle starts at the scope on which `$broadcast` was called. All
14846        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14847        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
14848        * scope and calls all registered listeners along the way. The event cannot be canceled.
14849        *
14850        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14851        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14852        *
14853        * @param {string} name Event name to broadcast.
14854        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14855        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
14856        */
14857       $broadcast: function(name, args) {
14858         var target = this,
14859             current = target,
14860             next = target,
14861             event = {
14862               name: name,
14863               targetScope: target,
14864               preventDefault: function() {
14865                 event.defaultPrevented = true;
14866               },
14867               defaultPrevented: false
14868             };
14869
14870         if (!target.$$listenerCount[name]) return event;
14871
14872         var listenerArgs = concat([event], arguments, 1),
14873             listeners, i, length;
14874
14875         //down while you can, then up and next sibling or up and next sibling until back at root
14876         while ((current = next)) {
14877           event.currentScope = current;
14878           listeners = current.$$listeners[name] || [];
14879           for (i = 0, length = listeners.length; i < length; i++) {
14880             // if listeners were deregistered, defragment the array
14881             if (!listeners[i]) {
14882               listeners.splice(i, 1);
14883               i--;
14884               length--;
14885               continue;
14886             }
14887
14888             try {
14889               listeners[i].apply(null, listenerArgs);
14890             } catch (e) {
14891               $exceptionHandler(e);
14892             }
14893           }
14894
14895           // Insanity Warning: scope depth-first traversal
14896           // yes, this code is a bit crazy, but it works and we have tests to prove it!
14897           // this piece should be kept in sync with the traversal in $digest
14898           // (though it differs due to having the extra check for $$listenerCount)
14899           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
14900               (current !== target && current.$$nextSibling)))) {
14901             while (current !== target && !(next = current.$$nextSibling)) {
14902               current = current.$parent;
14903             }
14904           }
14905         }
14906
14907         event.currentScope = null;
14908         return event;
14909       }
14910     };
14911
14912     var $rootScope = new Scope();
14913
14914     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
14915     var asyncQueue = $rootScope.$$asyncQueue = [];
14916     var postDigestQueue = $rootScope.$$postDigestQueue = [];
14917     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
14918
14919     return $rootScope;
14920
14921
14922     function beginPhase(phase) {
14923       if ($rootScope.$$phase) {
14924         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
14925       }
14926
14927       $rootScope.$$phase = phase;
14928     }
14929
14930     function clearPhase() {
14931       $rootScope.$$phase = null;
14932     }
14933
14934
14935     function decrementListenerCount(current, count, name) {
14936       do {
14937         current.$$listenerCount[name] -= count;
14938
14939         if (current.$$listenerCount[name] === 0) {
14940           delete current.$$listenerCount[name];
14941         }
14942       } while ((current = current.$parent));
14943     }
14944
14945     /**
14946      * function used as an initial value for watchers.
14947      * because it's unique we can easily tell it apart from other values
14948      */
14949     function initWatchVal() {}
14950
14951     function flushApplyAsync() {
14952       while (applyAsyncQueue.length) {
14953         try {
14954           applyAsyncQueue.shift()();
14955         } catch (e) {
14956           $exceptionHandler(e);
14957         }
14958       }
14959       applyAsyncId = null;
14960     }
14961
14962     function scheduleApplyAsync() {
14963       if (applyAsyncId === null) {
14964         applyAsyncId = $browser.defer(function() {
14965           $rootScope.$apply(flushApplyAsync);
14966         });
14967       }
14968     }
14969   }];
14970 }
14971
14972 /**
14973  * @description
14974  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
14975  */
14976 function $$SanitizeUriProvider() {
14977   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
14978     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
14979
14980   /**
14981    * @description
14982    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
14983    * urls during a[href] sanitization.
14984    *
14985    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
14986    *
14987    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
14988    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
14989    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
14990    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
14991    *
14992    * @param {RegExp=} regexp New regexp to whitelist urls with.
14993    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
14994    *    chaining otherwise.
14995    */
14996   this.aHrefSanitizationWhitelist = function(regexp) {
14997     if (isDefined(regexp)) {
14998       aHrefSanitizationWhitelist = regexp;
14999       return this;
15000     }
15001     return aHrefSanitizationWhitelist;
15002   };
15003
15004
15005   /**
15006    * @description
15007    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
15008    * urls during img[src] sanitization.
15009    *
15010    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
15011    *
15012    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
15013    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
15014    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
15015    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
15016    *
15017    * @param {RegExp=} regexp New regexp to whitelist urls with.
15018    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
15019    *    chaining otherwise.
15020    */
15021   this.imgSrcSanitizationWhitelist = function(regexp) {
15022     if (isDefined(regexp)) {
15023       imgSrcSanitizationWhitelist = regexp;
15024       return this;
15025     }
15026     return imgSrcSanitizationWhitelist;
15027   };
15028
15029   this.$get = function() {
15030     return function sanitizeUri(uri, isImage) {
15031       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
15032       var normalizedVal;
15033       normalizedVal = urlResolve(uri).href;
15034       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
15035         return 'unsafe:' + normalizedVal;
15036       }
15037       return uri;
15038     };
15039   };
15040 }
15041
15042 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15043  *     Any commits to this file should be reviewed with security in mind.  *
15044  *   Changes to this file can potentially create security vulnerabilities. *
15045  *          An approval from 2 Core members with history of modifying      *
15046  *                         this file is required.                          *
15047  *                                                                         *
15048  *  Does the change somehow allow for arbitrary javascript to be executed? *
15049  *    Or allows for someone to change the prototype of built-in objects?   *
15050  *     Or gives undesired access to variables likes document or window?    *
15051  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15052
15053 var $sceMinErr = minErr('$sce');
15054
15055 var SCE_CONTEXTS = {
15056   HTML: 'html',
15057   CSS: 'css',
15058   URL: 'url',
15059   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
15060   // url.  (e.g. ng-include, script src, templateUrl)
15061   RESOURCE_URL: 'resourceUrl',
15062   JS: 'js'
15063 };
15064
15065 // Helper functions follow.
15066
15067 function adjustMatcher(matcher) {
15068   if (matcher === 'self') {
15069     return matcher;
15070   } else if (isString(matcher)) {
15071     // Strings match exactly except for 2 wildcards - '*' and '**'.
15072     // '*' matches any character except those from the set ':/.?&'.
15073     // '**' matches any character (like .* in a RegExp).
15074     // More than 2 *'s raises an error as it's ill defined.
15075     if (matcher.indexOf('***') > -1) {
15076       throw $sceMinErr('iwcard',
15077           'Illegal sequence *** in string matcher.  String: {0}', matcher);
15078     }
15079     matcher = escapeForRegexp(matcher).
15080                   replace('\\*\\*', '.*').
15081                   replace('\\*', '[^:/.?&;]*');
15082     return new RegExp('^' + matcher + '$');
15083   } else if (isRegExp(matcher)) {
15084     // The only other type of matcher allowed is a Regexp.
15085     // Match entire URL / disallow partial matches.
15086     // Flags are reset (i.e. no global, ignoreCase or multiline)
15087     return new RegExp('^' + matcher.source + '$');
15088   } else {
15089     throw $sceMinErr('imatcher',
15090         'Matchers may only be "self", string patterns or RegExp objects');
15091   }
15092 }
15093
15094
15095 function adjustMatchers(matchers) {
15096   var adjustedMatchers = [];
15097   if (isDefined(matchers)) {
15098     forEach(matchers, function(matcher) {
15099       adjustedMatchers.push(adjustMatcher(matcher));
15100     });
15101   }
15102   return adjustedMatchers;
15103 }
15104
15105
15106 /**
15107  * @ngdoc service
15108  * @name $sceDelegate
15109  * @kind function
15110  *
15111  * @description
15112  *
15113  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
15114  * Contextual Escaping (SCE)} services to AngularJS.
15115  *
15116  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
15117  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
15118  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
15119  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
15120  * work because `$sce` delegates to `$sceDelegate` for these operations.
15121  *
15122  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
15123  *
15124  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
15125  * can override it completely to change the behavior of `$sce`, the common case would
15126  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
15127  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
15128  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
15129  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
15130  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
15131  */
15132
15133 /**
15134  * @ngdoc provider
15135  * @name $sceDelegateProvider
15136  * @description
15137  *
15138  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
15139  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
15140  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
15141  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
15142  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
15143  *
15144  * For the general details about this service in Angular, read the main page for {@link ng.$sce
15145  * Strict Contextual Escaping (SCE)}.
15146  *
15147  * **Example**:  Consider the following case. <a name="example"></a>
15148  *
15149  * - your app is hosted at url `http://myapp.example.com/`
15150  * - but some of your templates are hosted on other domains you control such as
15151  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
15152  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
15153  *
15154  * Here is what a secure configuration for this scenario might look like:
15155  *
15156  * ```
15157  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
15158  *    $sceDelegateProvider.resourceUrlWhitelist([
15159  *      // Allow same origin resource loads.
15160  *      'self',
15161  *      // Allow loading from our assets domain.  Notice the difference between * and **.
15162  *      'http://srv*.assets.example.com/**'
15163  *    ]);
15164  *
15165  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
15166  *    $sceDelegateProvider.resourceUrlBlacklist([
15167  *      'http://myapp.example.com/clickThru**'
15168  *    ]);
15169  *  });
15170  * ```
15171  */
15172
15173 function $SceDelegateProvider() {
15174   this.SCE_CONTEXTS = SCE_CONTEXTS;
15175
15176   // Resource URLs can also be trusted by policy.
15177   var resourceUrlWhitelist = ['self'],
15178       resourceUrlBlacklist = [];
15179
15180   /**
15181    * @ngdoc method
15182    * @name $sceDelegateProvider#resourceUrlWhitelist
15183    * @kind function
15184    *
15185    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
15186    *     provided.  This must be an array or null.  A snapshot of this array is used so further
15187    *     changes to the array are ignored.
15188    *
15189    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15190    *     allowed in this array.
15191    *
15192    *     Note: **an empty whitelist array will block all URLs**!
15193    *
15194    * @return {Array} the currently set whitelist array.
15195    *
15196    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
15197    * same origin resource requests.
15198    *
15199    * @description
15200    * Sets/Gets the whitelist of trusted resource URLs.
15201    */
15202   this.resourceUrlWhitelist = function(value) {
15203     if (arguments.length) {
15204       resourceUrlWhitelist = adjustMatchers(value);
15205     }
15206     return resourceUrlWhitelist;
15207   };
15208
15209   /**
15210    * @ngdoc method
15211    * @name $sceDelegateProvider#resourceUrlBlacklist
15212    * @kind function
15213    *
15214    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
15215    *     provided.  This must be an array or null.  A snapshot of this array is used so further
15216    *     changes to the array are ignored.
15217    *
15218    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15219    *     allowed in this array.
15220    *
15221    *     The typical usage for the blacklist is to **block
15222    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
15223    *     these would otherwise be trusted but actually return content from the redirected domain.
15224    *
15225    *     Finally, **the blacklist overrides the whitelist** and has the final say.
15226    *
15227    * @return {Array} the currently set blacklist array.
15228    *
15229    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
15230    * is no blacklist.)
15231    *
15232    * @description
15233    * Sets/Gets the blacklist of trusted resource URLs.
15234    */
15235
15236   this.resourceUrlBlacklist = function(value) {
15237     if (arguments.length) {
15238       resourceUrlBlacklist = adjustMatchers(value);
15239     }
15240     return resourceUrlBlacklist;
15241   };
15242
15243   this.$get = ['$injector', function($injector) {
15244
15245     var htmlSanitizer = function htmlSanitizer(html) {
15246       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15247     };
15248
15249     if ($injector.has('$sanitize')) {
15250       htmlSanitizer = $injector.get('$sanitize');
15251     }
15252
15253
15254     function matchUrl(matcher, parsedUrl) {
15255       if (matcher === 'self') {
15256         return urlIsSameOrigin(parsedUrl);
15257       } else {
15258         // definitely a regex.  See adjustMatchers()
15259         return !!matcher.exec(parsedUrl.href);
15260       }
15261     }
15262
15263     function isResourceUrlAllowedByPolicy(url) {
15264       var parsedUrl = urlResolve(url.toString());
15265       var i, n, allowed = false;
15266       // Ensure that at least one item from the whitelist allows this url.
15267       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
15268         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
15269           allowed = true;
15270           break;
15271         }
15272       }
15273       if (allowed) {
15274         // Ensure that no item from the blacklist blocked this url.
15275         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
15276           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
15277             allowed = false;
15278             break;
15279           }
15280         }
15281       }
15282       return allowed;
15283     }
15284
15285     function generateHolderType(Base) {
15286       var holderType = function TrustedValueHolderType(trustedValue) {
15287         this.$$unwrapTrustedValue = function() {
15288           return trustedValue;
15289         };
15290       };
15291       if (Base) {
15292         holderType.prototype = new Base();
15293       }
15294       holderType.prototype.valueOf = function sceValueOf() {
15295         return this.$$unwrapTrustedValue();
15296       };
15297       holderType.prototype.toString = function sceToString() {
15298         return this.$$unwrapTrustedValue().toString();
15299       };
15300       return holderType;
15301     }
15302
15303     var trustedValueHolderBase = generateHolderType(),
15304         byType = {};
15305
15306     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
15307     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
15308     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
15309     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
15310     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
15311
15312     /**
15313      * @ngdoc method
15314      * @name $sceDelegate#trustAs
15315      *
15316      * @description
15317      * Returns an object that is trusted by angular for use in specified strict
15318      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
15319      * attribute interpolation, any dom event binding attribute interpolation
15320      * such as for onclick,  etc.) that uses the provided value.
15321      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
15322      *
15323      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15324      *   resourceUrl, html, js and css.
15325      * @param {*} value The value that that should be considered trusted/safe.
15326      * @returns {*} A value that can be used to stand in for the provided `value` in places
15327      * where Angular expects a $sce.trustAs() return value.
15328      */
15329     function trustAs(type, trustedValue) {
15330       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15331       if (!Constructor) {
15332         throw $sceMinErr('icontext',
15333             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
15334             type, trustedValue);
15335       }
15336       if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
15337         return trustedValue;
15338       }
15339       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
15340       // mutable objects, we ensure here that the value passed in is actually a string.
15341       if (typeof trustedValue !== 'string') {
15342         throw $sceMinErr('itype',
15343             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
15344             type);
15345       }
15346       return new Constructor(trustedValue);
15347     }
15348
15349     /**
15350      * @ngdoc method
15351      * @name $sceDelegate#valueOf
15352      *
15353      * @description
15354      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
15355      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
15356      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
15357      *
15358      * If the passed parameter is not a value that had been returned by {@link
15359      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
15360      *
15361      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
15362      *      call or anything else.
15363      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
15364      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
15365      *     `value` unchanged.
15366      */
15367     function valueOf(maybeTrusted) {
15368       if (maybeTrusted instanceof trustedValueHolderBase) {
15369         return maybeTrusted.$$unwrapTrustedValue();
15370       } else {
15371         return maybeTrusted;
15372       }
15373     }
15374
15375     /**
15376      * @ngdoc method
15377      * @name $sceDelegate#getTrusted
15378      *
15379      * @description
15380      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
15381      * returns the originally supplied value if the queried context type is a supertype of the
15382      * created type.  If this condition isn't satisfied, throws an exception.
15383      *
15384      * @param {string} type The kind of context in which this value is to be used.
15385      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
15386      *     `$sceDelegate.trustAs`} call.
15387      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
15388      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
15389      */
15390     function getTrusted(type, maybeTrusted) {
15391       if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
15392         return maybeTrusted;
15393       }
15394       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15395       if (constructor && maybeTrusted instanceof constructor) {
15396         return maybeTrusted.$$unwrapTrustedValue();
15397       }
15398       // If we get here, then we may only take one of two actions.
15399       // 1. sanitize the value for the requested type, or
15400       // 2. throw an exception.
15401       if (type === SCE_CONTEXTS.RESOURCE_URL) {
15402         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
15403           return maybeTrusted;
15404         } else {
15405           throw $sceMinErr('insecurl',
15406               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
15407               maybeTrusted.toString());
15408         }
15409       } else if (type === SCE_CONTEXTS.HTML) {
15410         return htmlSanitizer(maybeTrusted);
15411       }
15412       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15413     }
15414
15415     return { trustAs: trustAs,
15416              getTrusted: getTrusted,
15417              valueOf: valueOf };
15418   }];
15419 }
15420
15421
15422 /**
15423  * @ngdoc provider
15424  * @name $sceProvider
15425  * @description
15426  *
15427  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
15428  * -   enable/disable Strict Contextual Escaping (SCE) in a module
15429  * -   override the default implementation with a custom delegate
15430  *
15431  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
15432  */
15433
15434 /* jshint maxlen: false*/
15435
15436 /**
15437  * @ngdoc service
15438  * @name $sce
15439  * @kind function
15440  *
15441  * @description
15442  *
15443  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
15444  *
15445  * # Strict Contextual Escaping
15446  *
15447  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
15448  * contexts to result in a value that is marked as safe to use for that context.  One example of
15449  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
15450  * to these contexts as privileged or SCE contexts.
15451  *
15452  * As of version 1.2, Angular ships with SCE enabled by default.
15453  *
15454  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
15455  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
15456  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
15457  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
15458  * to the top of your HTML document.
15459  *
15460  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
15461  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
15462  *
15463  * Here's an example of a binding in a privileged context:
15464  *
15465  * ```
15466  * <input ng-model="userHtml">
15467  * <div ng-bind-html="userHtml"></div>
15468  * ```
15469  *
15470  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
15471  * disabled, this application allows the user to render arbitrary HTML into the DIV.
15472  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
15473  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
15474  * security vulnerabilities.)
15475  *
15476  * For the case of HTML, you might use a library, either on the client side, or on the server side,
15477  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
15478  *
15479  * How would you ensure that every place that used these types of bindings was bound to a value that
15480  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
15481  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
15482  * properties/fields and forgot to update the binding to the sanitized value?
15483  *
15484  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
15485  * determine that something explicitly says it's safe to use a value for binding in that
15486  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
15487  * for those values that you can easily tell are safe - because they were received from your server,
15488  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
15489  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
15490  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
15491  *
15492  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
15493  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
15494  * obtain values that will be accepted by SCE / privileged contexts.
15495  *
15496  *
15497  * ## How does it work?
15498  *
15499  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
15500  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
15501  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
15502  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
15503  *
15504  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
15505  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
15506  * simplified):
15507  *
15508  * ```
15509  * var ngBindHtmlDirective = ['$sce', function($sce) {
15510  *   return function(scope, element, attr) {
15511  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
15512  *       element.html(value || '');
15513  *     });
15514  *   };
15515  * }];
15516  * ```
15517  *
15518  * ## Impact on loading templates
15519  *
15520  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
15521  * `templateUrl`'s specified by {@link guide/directive directives}.
15522  *
15523  * By default, Angular only loads templates from the same domain and protocol as the application
15524  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
15525  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
15526  * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
15527  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
15528  *
15529  * *Please note*:
15530  * The browser's
15531  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
15532  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
15533  * policy apply in addition to this and may further restrict whether the template is successfully
15534  * loaded.  This means that without the right CORS policy, loading templates from a different domain
15535  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
15536  * browsers.
15537  *
15538  * ## This feels like too much overhead
15539  *
15540  * It's important to remember that SCE only applies to interpolation expressions.
15541  *
15542  * If your expressions are constant literals, they're automatically trusted and you don't need to
15543  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
15544  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
15545  *
15546  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
15547  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
15548  *
15549  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
15550  * templates in `ng-include` from your application's domain without having to even know about SCE.
15551  * It blocks loading templates from other domains or loading templates over http from an https
15552  * served document.  You can change these by setting your own custom {@link
15553  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
15554  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
15555  *
15556  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
15557  * application that's secure and can be audited to verify that with much more ease than bolting
15558  * security onto an application later.
15559  *
15560  * <a name="contexts"></a>
15561  * ## What trusted context types are supported?
15562  *
15563  * | Context             | Notes          |
15564  * |---------------------|----------------|
15565  * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
15566  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
15567  * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
15568  * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
15569  * | `$sce.JS`           | For JavaScript that is safe to execute in your application's context.  Currently unused.  Feel free to use it in your own directives. |
15570  *
15571  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
15572  *
15573  *  Each element in these arrays must be one of the following:
15574  *
15575  *  - **'self'**
15576  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
15577  *      domain** as the application document using the **same protocol**.
15578  *  - **String** (except the special value `'self'`)
15579  *    - The string is matched against the full *normalized / absolute URL* of the resource
15580  *      being tested (substring matches are not good enough.)
15581  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
15582  *      match themselves.
15583  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
15584  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
15585  *      in a whitelist.
15586  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
15587  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
15588  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
15589  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
15590  *      http://foo.example.com/templates/**).
15591  *  - **RegExp** (*see caveat below*)
15592  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
15593  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
15594  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
15595  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
15596  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
15597  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
15598  *      is highly recommended to use the string patterns and only fall back to regular expressions
15599  *      as a last resort.
15600  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
15601  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
15602  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
15603  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
15604  *    - If you are generating your JavaScript from some other templating engine (not
15605  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
15606  *      remember to escape your regular expression (and be aware that you might need more than
15607  *      one level of escaping depending on your templating engine and the way you interpolated
15608  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
15609  *      enough before coding your own.  E.g. Ruby has
15610  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
15611  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
15612  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
15613  *      Closure library's [goog.string.regExpEscape(s)](
15614  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
15615  *
15616  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
15617  *
15618  * ## Show me an example using SCE.
15619  *
15620  * <example module="mySceApp" deps="angular-sanitize.js">
15621  * <file name="index.html">
15622  *   <div ng-controller="AppController as myCtrl">
15623  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
15624  *     <b>User comments</b><br>
15625  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
15626  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
15627  *     exploit.
15628  *     <div class="well">
15629  *       <div ng-repeat="userComment in myCtrl.userComments">
15630  *         <b>{{userComment.name}}</b>:
15631  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
15632  *         <br>
15633  *       </div>
15634  *     </div>
15635  *   </div>
15636  * </file>
15637  *
15638  * <file name="script.js">
15639  *   angular.module('mySceApp', ['ngSanitize'])
15640  *     .controller('AppController', ['$http', '$templateCache', '$sce',
15641  *       function($http, $templateCache, $sce) {
15642  *         var self = this;
15643  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
15644  *           self.userComments = userComments;
15645  *         });
15646  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
15647  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15648  *             'sanitization.&quot;">Hover over this text.</span>');
15649  *       }]);
15650  * </file>
15651  *
15652  * <file name="test_data.json">
15653  * [
15654  *   { "name": "Alice",
15655  *     "htmlComment":
15656  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
15657  *   },
15658  *   { "name": "Bob",
15659  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
15660  *   }
15661  * ]
15662  * </file>
15663  *
15664  * <file name="protractor.js" type="protractor">
15665  *   describe('SCE doc demo', function() {
15666  *     it('should sanitize untrusted values', function() {
15667  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
15668  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
15669  *     });
15670  *
15671  *     it('should NOT sanitize explicitly trusted values', function() {
15672  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
15673  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15674  *           'sanitization.&quot;">Hover over this text.</span>');
15675  *     });
15676  *   });
15677  * </file>
15678  * </example>
15679  *
15680  *
15681  *
15682  * ## Can I disable SCE completely?
15683  *
15684  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
15685  * for little coding overhead.  It will be much harder to take an SCE disabled application and
15686  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
15687  * for cases where you have a lot of existing code that was written before SCE was introduced and
15688  * you're migrating them a module at a time.
15689  *
15690  * That said, here's how you can completely disable SCE:
15691  *
15692  * ```
15693  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
15694  *   // Completely disable SCE.  For demonstration purposes only!
15695  *   // Do not use in new projects.
15696  *   $sceProvider.enabled(false);
15697  * });
15698  * ```
15699  *
15700  */
15701 /* jshint maxlen: 100 */
15702
15703 function $SceProvider() {
15704   var enabled = true;
15705
15706   /**
15707    * @ngdoc method
15708    * @name $sceProvider#enabled
15709    * @kind function
15710    *
15711    * @param {boolean=} value If provided, then enables/disables SCE.
15712    * @return {boolean} true if SCE is enabled, false otherwise.
15713    *
15714    * @description
15715    * Enables/disables SCE and returns the current value.
15716    */
15717   this.enabled = function(value) {
15718     if (arguments.length) {
15719       enabled = !!value;
15720     }
15721     return enabled;
15722   };
15723
15724
15725   /* Design notes on the default implementation for SCE.
15726    *
15727    * The API contract for the SCE delegate
15728    * -------------------------------------
15729    * The SCE delegate object must provide the following 3 methods:
15730    *
15731    * - trustAs(contextEnum, value)
15732    *     This method is used to tell the SCE service that the provided value is OK to use in the
15733    *     contexts specified by contextEnum.  It must return an object that will be accepted by
15734    *     getTrusted() for a compatible contextEnum and return this value.
15735    *
15736    * - valueOf(value)
15737    *     For values that were not produced by trustAs(), return them as is.  For values that were
15738    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
15739    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
15740    *     such a value.
15741    *
15742    * - getTrusted(contextEnum, value)
15743    *     This function should return the a value that is safe to use in the context specified by
15744    *     contextEnum or throw and exception otherwise.
15745    *
15746    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
15747    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
15748    * instance, an implementation could maintain a registry of all trusted objects by context.  In
15749    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
15750    * return the same object passed in if it was found in the registry under a compatible context or
15751    * throw an exception otherwise.  An implementation might only wrap values some of the time based
15752    * on some criteria.  getTrusted() might return a value and not throw an exception for special
15753    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
15754    *
15755    *
15756    * A note on the inheritance model for SCE contexts
15757    * ------------------------------------------------
15758    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
15759    * is purely an implementation details.
15760    *
15761    * The contract is simply this:
15762    *
15763    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
15764    *     will also succeed.
15765    *
15766    * Inheritance happens to capture this in a natural way.  In some future, we
15767    * may not use inheritance anymore.  That is OK because no code outside of
15768    * sce.js and sceSpecs.js would need to be aware of this detail.
15769    */
15770
15771   this.$get = ['$parse', '$sceDelegate', function(
15772                 $parse,   $sceDelegate) {
15773     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
15774     // the "expression(javascript expression)" syntax which is insecure.
15775     if (enabled && msie < 8) {
15776       throw $sceMinErr('iequirks',
15777         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
15778         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
15779         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
15780     }
15781
15782     var sce = shallowCopy(SCE_CONTEXTS);
15783
15784     /**
15785      * @ngdoc method
15786      * @name $sce#isEnabled
15787      * @kind function
15788      *
15789      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
15790      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
15791      *
15792      * @description
15793      * Returns a boolean indicating if SCE is enabled.
15794      */
15795     sce.isEnabled = function() {
15796       return enabled;
15797     };
15798     sce.trustAs = $sceDelegate.trustAs;
15799     sce.getTrusted = $sceDelegate.getTrusted;
15800     sce.valueOf = $sceDelegate.valueOf;
15801
15802     if (!enabled) {
15803       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
15804       sce.valueOf = identity;
15805     }
15806
15807     /**
15808      * @ngdoc method
15809      * @name $sce#parseAs
15810      *
15811      * @description
15812      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
15813      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
15814      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
15815      * *result*)}
15816      *
15817      * @param {string} type The kind of SCE context in which this result will be used.
15818      * @param {string} expression String expression to compile.
15819      * @returns {function(context, locals)} a function which represents the compiled expression:
15820      *
15821      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15822      *      are evaluated against (typically a scope object).
15823      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15824      *      `context`.
15825      */
15826     sce.parseAs = function sceParseAs(type, expr) {
15827       var parsed = $parse(expr);
15828       if (parsed.literal && parsed.constant) {
15829         return parsed;
15830       } else {
15831         return $parse(expr, function(value) {
15832           return sce.getTrusted(type, value);
15833         });
15834       }
15835     };
15836
15837     /**
15838      * @ngdoc method
15839      * @name $sce#trustAs
15840      *
15841      * @description
15842      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
15843      * returns an object that is trusted by angular for use in specified strict contextual
15844      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
15845      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
15846      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
15847      * escaping.
15848      *
15849      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15850      *   resource_url, html, js and css.
15851      * @param {*} value The value that that should be considered trusted/safe.
15852      * @returns {*} A value that can be used to stand in for the provided `value` in places
15853      * where Angular expects a $sce.trustAs() return value.
15854      */
15855
15856     /**
15857      * @ngdoc method
15858      * @name $sce#trustAsHtml
15859      *
15860      * @description
15861      * Shorthand method.  `$sce.trustAsHtml(value)` →
15862      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
15863      *
15864      * @param {*} value The value to trustAs.
15865      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
15866      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
15867      *     only accept expressions that are either literal constants or are the
15868      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15869      */
15870
15871     /**
15872      * @ngdoc method
15873      * @name $sce#trustAsUrl
15874      *
15875      * @description
15876      * Shorthand method.  `$sce.trustAsUrl(value)` →
15877      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
15878      *
15879      * @param {*} value The value to trustAs.
15880      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
15881      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
15882      *     only accept expressions that are either literal constants or are the
15883      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15884      */
15885
15886     /**
15887      * @ngdoc method
15888      * @name $sce#trustAsResourceUrl
15889      *
15890      * @description
15891      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
15892      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
15893      *
15894      * @param {*} value The value to trustAs.
15895      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
15896      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
15897      *     only accept expressions that are either literal constants or are the return
15898      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
15899      */
15900
15901     /**
15902      * @ngdoc method
15903      * @name $sce#trustAsJs
15904      *
15905      * @description
15906      * Shorthand method.  `$sce.trustAsJs(value)` →
15907      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
15908      *
15909      * @param {*} value The value to trustAs.
15910      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
15911      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
15912      *     only accept expressions that are either literal constants or are the
15913      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15914      */
15915
15916     /**
15917      * @ngdoc method
15918      * @name $sce#getTrusted
15919      *
15920      * @description
15921      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
15922      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
15923      * originally supplied value if the queried context type is a supertype of the created type.
15924      * If this condition isn't satisfied, throws an exception.
15925      *
15926      * @param {string} type The kind of context in which this value is to be used.
15927      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
15928      *                         call.
15929      * @returns {*} The value the was originally provided to
15930      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
15931      *              Otherwise, throws an exception.
15932      */
15933
15934     /**
15935      * @ngdoc method
15936      * @name $sce#getTrustedHtml
15937      *
15938      * @description
15939      * Shorthand method.  `$sce.getTrustedHtml(value)` →
15940      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
15941      *
15942      * @param {*} value The value to pass to `$sce.getTrusted`.
15943      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
15944      */
15945
15946     /**
15947      * @ngdoc method
15948      * @name $sce#getTrustedCss
15949      *
15950      * @description
15951      * Shorthand method.  `$sce.getTrustedCss(value)` →
15952      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
15953      *
15954      * @param {*} value The value to pass to `$sce.getTrusted`.
15955      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
15956      */
15957
15958     /**
15959      * @ngdoc method
15960      * @name $sce#getTrustedUrl
15961      *
15962      * @description
15963      * Shorthand method.  `$sce.getTrustedUrl(value)` →
15964      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
15965      *
15966      * @param {*} value The value to pass to `$sce.getTrusted`.
15967      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
15968      */
15969
15970     /**
15971      * @ngdoc method
15972      * @name $sce#getTrustedResourceUrl
15973      *
15974      * @description
15975      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
15976      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
15977      *
15978      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
15979      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
15980      */
15981
15982     /**
15983      * @ngdoc method
15984      * @name $sce#getTrustedJs
15985      *
15986      * @description
15987      * Shorthand method.  `$sce.getTrustedJs(value)` →
15988      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
15989      *
15990      * @param {*} value The value to pass to `$sce.getTrusted`.
15991      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
15992      */
15993
15994     /**
15995      * @ngdoc method
15996      * @name $sce#parseAsHtml
15997      *
15998      * @description
15999      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
16000      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
16001      *
16002      * @param {string} expression String expression to compile.
16003      * @returns {function(context, locals)} a function which represents the compiled expression:
16004      *
16005      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16006      *      are evaluated against (typically a scope object).
16007      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16008      *      `context`.
16009      */
16010
16011     /**
16012      * @ngdoc method
16013      * @name $sce#parseAsCss
16014      *
16015      * @description
16016      * Shorthand method.  `$sce.parseAsCss(value)` →
16017      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
16018      *
16019      * @param {string} expression String expression to compile.
16020      * @returns {function(context, locals)} a function which represents the compiled expression:
16021      *
16022      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16023      *      are evaluated against (typically a scope object).
16024      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16025      *      `context`.
16026      */
16027
16028     /**
16029      * @ngdoc method
16030      * @name $sce#parseAsUrl
16031      *
16032      * @description
16033      * Shorthand method.  `$sce.parseAsUrl(value)` →
16034      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
16035      *
16036      * @param {string} expression String expression to compile.
16037      * @returns {function(context, locals)} a function which represents the compiled expression:
16038      *
16039      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16040      *      are evaluated against (typically a scope object).
16041      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16042      *      `context`.
16043      */
16044
16045     /**
16046      * @ngdoc method
16047      * @name $sce#parseAsResourceUrl
16048      *
16049      * @description
16050      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
16051      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
16052      *
16053      * @param {string} expression String expression to compile.
16054      * @returns {function(context, locals)} a function which represents the compiled expression:
16055      *
16056      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16057      *      are evaluated against (typically a scope object).
16058      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16059      *      `context`.
16060      */
16061
16062     /**
16063      * @ngdoc method
16064      * @name $sce#parseAsJs
16065      *
16066      * @description
16067      * Shorthand method.  `$sce.parseAsJs(value)` →
16068      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
16069      *
16070      * @param {string} expression String expression to compile.
16071      * @returns {function(context, locals)} a function which represents the compiled expression:
16072      *
16073      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16074      *      are evaluated against (typically a scope object).
16075      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16076      *      `context`.
16077      */
16078
16079     // Shorthand delegations.
16080     var parse = sce.parseAs,
16081         getTrusted = sce.getTrusted,
16082         trustAs = sce.trustAs;
16083
16084     forEach(SCE_CONTEXTS, function(enumValue, name) {
16085       var lName = lowercase(name);
16086       sce[camelCase("parse_as_" + lName)] = function(expr) {
16087         return parse(enumValue, expr);
16088       };
16089       sce[camelCase("get_trusted_" + lName)] = function(value) {
16090         return getTrusted(enumValue, value);
16091       };
16092       sce[camelCase("trust_as_" + lName)] = function(value) {
16093         return trustAs(enumValue, value);
16094       };
16095     });
16096
16097     return sce;
16098   }];
16099 }
16100
16101 /**
16102  * !!! This is an undocumented "private" service !!!
16103  *
16104  * @name $sniffer
16105  * @requires $window
16106  * @requires $document
16107  *
16108  * @property {boolean} history Does the browser support html5 history api ?
16109  * @property {boolean} transitions Does the browser support CSS transition events ?
16110  * @property {boolean} animations Does the browser support CSS animation events ?
16111  *
16112  * @description
16113  * This is very simple implementation of testing browser's features.
16114  */
16115 function $SnifferProvider() {
16116   this.$get = ['$window', '$document', function($window, $document) {
16117     var eventSupport = {},
16118         android =
16119           int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
16120         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
16121         document = $document[0] || {},
16122         vendorPrefix,
16123         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
16124         bodyStyle = document.body && document.body.style,
16125         transitions = false,
16126         animations = false,
16127         match;
16128
16129     if (bodyStyle) {
16130       for (var prop in bodyStyle) {
16131         if (match = vendorRegex.exec(prop)) {
16132           vendorPrefix = match[0];
16133           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
16134           break;
16135         }
16136       }
16137
16138       if (!vendorPrefix) {
16139         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
16140       }
16141
16142       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
16143       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
16144
16145       if (android && (!transitions ||  !animations)) {
16146         transitions = isString(document.body.style.webkitTransition);
16147         animations = isString(document.body.style.webkitAnimation);
16148       }
16149     }
16150
16151
16152     return {
16153       // Android has history.pushState, but it does not update location correctly
16154       // so let's not use the history API at all.
16155       // http://code.google.com/p/android/issues/detail?id=17471
16156       // https://github.com/angular/angular.js/issues/904
16157
16158       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
16159       // so let's not use the history API also
16160       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
16161       // jshint -W018
16162       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
16163       // jshint +W018
16164       hasEvent: function(event) {
16165         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
16166         // it. In particular the event is not fired when backspace or delete key are pressed or
16167         // when cut operation is performed.
16168         // IE10+ implements 'input' event but it erroneously fires under various situations,
16169         // e.g. when placeholder changes, or a form is focused.
16170         if (event === 'input' && msie <= 11) return false;
16171
16172         if (isUndefined(eventSupport[event])) {
16173           var divElm = document.createElement('div');
16174           eventSupport[event] = 'on' + event in divElm;
16175         }
16176
16177         return eventSupport[event];
16178       },
16179       csp: csp(),
16180       vendorPrefix: vendorPrefix,
16181       transitions: transitions,
16182       animations: animations,
16183       android: android
16184     };
16185   }];
16186 }
16187
16188 var $compileMinErr = minErr('$compile');
16189
16190 /**
16191  * @ngdoc service
16192  * @name $templateRequest
16193  *
16194  * @description
16195  * The `$templateRequest` service runs security checks then downloads the provided template using
16196  * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
16197  * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
16198  * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
16199  * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
16200  * when `tpl` is of type string and `$templateCache` has the matching entry.
16201  *
16202  * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
16203  * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
16204  *
16205  * @return {Promise} the HTTP Promise for the given.
16206  *
16207  * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
16208  */
16209 function $TemplateRequestProvider() {
16210   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
16211     function handleRequestFn(tpl, ignoreRequestError) {
16212       handleRequestFn.totalPendingRequests++;
16213
16214       // We consider the template cache holds only trusted templates, so
16215       // there's no need to go through whitelisting again for keys that already
16216       // are included in there. This also makes Angular accept any script
16217       // directive, no matter its name. However, we still need to unwrap trusted
16218       // types.
16219       if (!isString(tpl) || !$templateCache.get(tpl)) {
16220         tpl = $sce.getTrustedResourceUrl(tpl);
16221       }
16222
16223       var transformResponse = $http.defaults && $http.defaults.transformResponse;
16224
16225       if (isArray(transformResponse)) {
16226         transformResponse = transformResponse.filter(function(transformer) {
16227           return transformer !== defaultHttpResponseTransform;
16228         });
16229       } else if (transformResponse === defaultHttpResponseTransform) {
16230         transformResponse = null;
16231       }
16232
16233       var httpOptions = {
16234         cache: $templateCache,
16235         transformResponse: transformResponse
16236       };
16237
16238       return $http.get(tpl, httpOptions)
16239         ['finally'](function() {
16240           handleRequestFn.totalPendingRequests--;
16241         })
16242         .then(function(response) {
16243           return response.data;
16244         }, handleError);
16245
16246       function handleError(resp) {
16247         if (!ignoreRequestError) {
16248           throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
16249         }
16250         return $q.reject(resp);
16251       }
16252     }
16253
16254     handleRequestFn.totalPendingRequests = 0;
16255
16256     return handleRequestFn;
16257   }];
16258 }
16259
16260 function $$TestabilityProvider() {
16261   this.$get = ['$rootScope', '$browser', '$location',
16262        function($rootScope,   $browser,   $location) {
16263
16264     /**
16265      * @name $testability
16266      *
16267      * @description
16268      * The private $$testability service provides a collection of methods for use when debugging
16269      * or by automated test and debugging tools.
16270      */
16271     var testability = {};
16272
16273     /**
16274      * @name $$testability#findBindings
16275      *
16276      * @description
16277      * Returns an array of elements that are bound (via ng-bind or {{}})
16278      * to expressions matching the input.
16279      *
16280      * @param {Element} element The element root to search from.
16281      * @param {string} expression The binding expression to match.
16282      * @param {boolean} opt_exactMatch If true, only returns exact matches
16283      *     for the expression. Filters and whitespace are ignored.
16284      */
16285     testability.findBindings = function(element, expression, opt_exactMatch) {
16286       var bindings = element.getElementsByClassName('ng-binding');
16287       var matches = [];
16288       forEach(bindings, function(binding) {
16289         var dataBinding = angular.element(binding).data('$binding');
16290         if (dataBinding) {
16291           forEach(dataBinding, function(bindingName) {
16292             if (opt_exactMatch) {
16293               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
16294               if (matcher.test(bindingName)) {
16295                 matches.push(binding);
16296               }
16297             } else {
16298               if (bindingName.indexOf(expression) != -1) {
16299                 matches.push(binding);
16300               }
16301             }
16302           });
16303         }
16304       });
16305       return matches;
16306     };
16307
16308     /**
16309      * @name $$testability#findModels
16310      *
16311      * @description
16312      * Returns an array of elements that are two-way found via ng-model to
16313      * expressions matching the input.
16314      *
16315      * @param {Element} element The element root to search from.
16316      * @param {string} expression The model expression to match.
16317      * @param {boolean} opt_exactMatch If true, only returns exact matches
16318      *     for the expression.
16319      */
16320     testability.findModels = function(element, expression, opt_exactMatch) {
16321       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
16322       for (var p = 0; p < prefixes.length; ++p) {
16323         var attributeEquals = opt_exactMatch ? '=' : '*=';
16324         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
16325         var elements = element.querySelectorAll(selector);
16326         if (elements.length) {
16327           return elements;
16328         }
16329       }
16330     };
16331
16332     /**
16333      * @name $$testability#getLocation
16334      *
16335      * @description
16336      * Shortcut for getting the location in a browser agnostic way. Returns
16337      *     the path, search, and hash. (e.g. /path?a=b#hash)
16338      */
16339     testability.getLocation = function() {
16340       return $location.url();
16341     };
16342
16343     /**
16344      * @name $$testability#setLocation
16345      *
16346      * @description
16347      * Shortcut for navigating to a location without doing a full page reload.
16348      *
16349      * @param {string} url The location url (path, search and hash,
16350      *     e.g. /path?a=b#hash) to go to.
16351      */
16352     testability.setLocation = function(url) {
16353       if (url !== $location.url()) {
16354         $location.url(url);
16355         $rootScope.$digest();
16356       }
16357     };
16358
16359     /**
16360      * @name $$testability#whenStable
16361      *
16362      * @description
16363      * Calls the callback when $timeout and $http requests are completed.
16364      *
16365      * @param {function} callback
16366      */
16367     testability.whenStable = function(callback) {
16368       $browser.notifyWhenNoOutstandingRequests(callback);
16369     };
16370
16371     return testability;
16372   }];
16373 }
16374
16375 function $TimeoutProvider() {
16376   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
16377        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
16378     var deferreds = {};
16379
16380
16381      /**
16382       * @ngdoc service
16383       * @name $timeout
16384       *
16385       * @description
16386       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
16387       * block and delegates any exceptions to
16388       * {@link ng.$exceptionHandler $exceptionHandler} service.
16389       *
16390       * The return value of registering a timeout function is a promise, which will be resolved when
16391       * the timeout is reached and the timeout function is executed.
16392       *
16393       * To cancel a timeout request, call `$timeout.cancel(promise)`.
16394       *
16395       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
16396       * synchronously flush the queue of deferred functions.
16397       *
16398       * @param {function()} fn A function, whose execution should be delayed.
16399       * @param {number=} [delay=0] Delay in milliseconds.
16400       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
16401       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
16402       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
16403       *   promise will be resolved with is the return value of the `fn` function.
16404       *
16405       */
16406     function timeout(fn, delay, invokeApply) {
16407       var skipApply = (isDefined(invokeApply) && !invokeApply),
16408           deferred = (skipApply ? $$q : $q).defer(),
16409           promise = deferred.promise,
16410           timeoutId;
16411
16412       timeoutId = $browser.defer(function() {
16413         try {
16414           deferred.resolve(fn());
16415         } catch (e) {
16416           deferred.reject(e);
16417           $exceptionHandler(e);
16418         }
16419         finally {
16420           delete deferreds[promise.$$timeoutId];
16421         }
16422
16423         if (!skipApply) $rootScope.$apply();
16424       }, delay);
16425
16426       promise.$$timeoutId = timeoutId;
16427       deferreds[timeoutId] = deferred;
16428
16429       return promise;
16430     }
16431
16432
16433      /**
16434       * @ngdoc method
16435       * @name $timeout#cancel
16436       *
16437       * @description
16438       * Cancels a task associated with the `promise`. As a result of this, the promise will be
16439       * resolved with a rejection.
16440       *
16441       * @param {Promise=} promise Promise returned by the `$timeout` function.
16442       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
16443       *   canceled.
16444       */
16445     timeout.cancel = function(promise) {
16446       if (promise && promise.$$timeoutId in deferreds) {
16447         deferreds[promise.$$timeoutId].reject('canceled');
16448         delete deferreds[promise.$$timeoutId];
16449         return $browser.defer.cancel(promise.$$timeoutId);
16450       }
16451       return false;
16452     };
16453
16454     return timeout;
16455   }];
16456 }
16457
16458 // NOTE:  The usage of window and document instead of $window and $document here is
16459 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
16460 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
16461 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
16462 // doesn't know about mocked locations and resolves URLs to the real document - which is
16463 // exactly the behavior needed here.  There is little value is mocking these out for this
16464 // service.
16465 var urlParsingNode = document.createElement("a");
16466 var originUrl = urlResolve(window.location.href);
16467
16468
16469 /**
16470  *
16471  * Implementation Notes for non-IE browsers
16472  * ----------------------------------------
16473  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
16474  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
16475  * URL will be resolved into an absolute URL in the context of the application document.
16476  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
16477  * properties are all populated to reflect the normalized URL.  This approach has wide
16478  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
16479  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16480  *
16481  * Implementation Notes for IE
16482  * ---------------------------
16483  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
16484  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
16485  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
16486  * work around that by performing the parsing in a 2nd step by taking a previously normalized
16487  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
16488  * properties such as protocol, hostname, port, etc.
16489  *
16490  * References:
16491  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
16492  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16493  *   http://url.spec.whatwg.org/#urlutils
16494  *   https://github.com/angular/angular.js/pull/2902
16495  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
16496  *
16497  * @kind function
16498  * @param {string} url The URL to be parsed.
16499  * @description Normalizes and parses a URL.
16500  * @returns {object} Returns the normalized URL as a dictionary.
16501  *
16502  *   | member name   | Description    |
16503  *   |---------------|----------------|
16504  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
16505  *   | protocol      | The protocol including the trailing colon                              |
16506  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
16507  *   | search        | The search params, minus the question mark                             |
16508  *   | hash          | The hash string, minus the hash symbol
16509  *   | hostname      | The hostname
16510  *   | port          | The port, without ":"
16511  *   | pathname      | The pathname, beginning with "/"
16512  *
16513  */
16514 function urlResolve(url) {
16515   var href = url;
16516
16517   if (msie) {
16518     // Normalize before parse.  Refer Implementation Notes on why this is
16519     // done in two steps on IE.
16520     urlParsingNode.setAttribute("href", href);
16521     href = urlParsingNode.href;
16522   }
16523
16524   urlParsingNode.setAttribute('href', href);
16525
16526   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
16527   return {
16528     href: urlParsingNode.href,
16529     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
16530     host: urlParsingNode.host,
16531     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
16532     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
16533     hostname: urlParsingNode.hostname,
16534     port: urlParsingNode.port,
16535     pathname: (urlParsingNode.pathname.charAt(0) === '/')
16536       ? urlParsingNode.pathname
16537       : '/' + urlParsingNode.pathname
16538   };
16539 }
16540
16541 /**
16542  * Parse a request URL and determine whether this is a same-origin request as the application document.
16543  *
16544  * @param {string|object} requestUrl The url of the request as a string that will be resolved
16545  * or a parsed URL object.
16546  * @returns {boolean} Whether the request is for the same origin as the application document.
16547  */
16548 function urlIsSameOrigin(requestUrl) {
16549   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
16550   return (parsed.protocol === originUrl.protocol &&
16551           parsed.host === originUrl.host);
16552 }
16553
16554 /**
16555  * @ngdoc service
16556  * @name $window
16557  *
16558  * @description
16559  * A reference to the browser's `window` object. While `window`
16560  * is globally available in JavaScript, it causes testability problems, because
16561  * it is a global variable. In angular we always refer to it through the
16562  * `$window` service, so it may be overridden, removed or mocked for testing.
16563  *
16564  * Expressions, like the one defined for the `ngClick` directive in the example
16565  * below, are evaluated with respect to the current scope.  Therefore, there is
16566  * no risk of inadvertently coding in a dependency on a global value in such an
16567  * expression.
16568  *
16569  * @example
16570    <example module="windowExample">
16571      <file name="index.html">
16572        <script>
16573          angular.module('windowExample', [])
16574            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
16575              $scope.greeting = 'Hello, World!';
16576              $scope.doGreeting = function(greeting) {
16577                $window.alert(greeting);
16578              };
16579            }]);
16580        </script>
16581        <div ng-controller="ExampleController">
16582          <input type="text" ng-model="greeting" />
16583          <button ng-click="doGreeting(greeting)">ALERT</button>
16584        </div>
16585      </file>
16586      <file name="protractor.js" type="protractor">
16587       it('should display the greeting in the input box', function() {
16588        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
16589        // If we click the button it will block the test runner
16590        // element(':button').click();
16591       });
16592      </file>
16593    </example>
16594  */
16595 function $WindowProvider() {
16596   this.$get = valueFn(window);
16597 }
16598
16599 /* global currencyFilter: true,
16600  dateFilter: true,
16601  filterFilter: true,
16602  jsonFilter: true,
16603  limitToFilter: true,
16604  lowercaseFilter: true,
16605  numberFilter: true,
16606  orderByFilter: true,
16607  uppercaseFilter: true,
16608  */
16609
16610 /**
16611  * @ngdoc provider
16612  * @name $filterProvider
16613  * @description
16614  *
16615  * Filters are just functions which transform input to an output. However filters need to be
16616  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
16617  * annotated with dependencies and is responsible for creating a filter function.
16618  *
16619  * <div class="alert alert-warning">
16620  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
16621  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
16622  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
16623  * (`myapp_subsection_filterx`).
16624  * </div>
16625  *
16626  * ```js
16627  *   // Filter registration
16628  *   function MyModule($provide, $filterProvider) {
16629  *     // create a service to demonstrate injection (not always needed)
16630  *     $provide.value('greet', function(name){
16631  *       return 'Hello ' + name + '!';
16632  *     });
16633  *
16634  *     // register a filter factory which uses the
16635  *     // greet service to demonstrate DI.
16636  *     $filterProvider.register('greet', function(greet){
16637  *       // return the filter function which uses the greet service
16638  *       // to generate salutation
16639  *       return function(text) {
16640  *         // filters need to be forgiving so check input validity
16641  *         return text && greet(text) || text;
16642  *       };
16643  *     });
16644  *   }
16645  * ```
16646  *
16647  * The filter function is registered with the `$injector` under the filter name suffix with
16648  * `Filter`.
16649  *
16650  * ```js
16651  *   it('should be the same instance', inject(
16652  *     function($filterProvider) {
16653  *       $filterProvider.register('reverse', function(){
16654  *         return ...;
16655  *       });
16656  *     },
16657  *     function($filter, reverseFilter) {
16658  *       expect($filter('reverse')).toBe(reverseFilter);
16659  *     });
16660  * ```
16661  *
16662  *
16663  * For more information about how angular filters work, and how to create your own filters, see
16664  * {@link guide/filter Filters} in the Angular Developer Guide.
16665  */
16666
16667 /**
16668  * @ngdoc service
16669  * @name $filter
16670  * @kind function
16671  * @description
16672  * Filters are used for formatting data displayed to the user.
16673  *
16674  * The general syntax in templates is as follows:
16675  *
16676  *         {{ expression [| filter_name[:parameter_value] ... ] }}
16677  *
16678  * @param {String} name Name of the filter function to retrieve
16679  * @return {Function} the filter function
16680  * @example
16681    <example name="$filter" module="filterExample">
16682      <file name="index.html">
16683        <div ng-controller="MainCtrl">
16684         <h3>{{ originalText }}</h3>
16685         <h3>{{ filteredText }}</h3>
16686        </div>
16687      </file>
16688
16689      <file name="script.js">
16690       angular.module('filterExample', [])
16691       .controller('MainCtrl', function($scope, $filter) {
16692         $scope.originalText = 'hello';
16693         $scope.filteredText = $filter('uppercase')($scope.originalText);
16694       });
16695      </file>
16696    </example>
16697   */
16698 $FilterProvider.$inject = ['$provide'];
16699 function $FilterProvider($provide) {
16700   var suffix = 'Filter';
16701
16702   /**
16703    * @ngdoc method
16704    * @name $filterProvider#register
16705    * @param {string|Object} name Name of the filter function, or an object map of filters where
16706    *    the keys are the filter names and the values are the filter factories.
16707    *
16708    *    <div class="alert alert-warning">
16709    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
16710    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
16711    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
16712    *    (`myapp_subsection_filterx`).
16713    *    </div>
16714    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
16715    *    of the registered filter instances.
16716    */
16717   function register(name, factory) {
16718     if (isObject(name)) {
16719       var filters = {};
16720       forEach(name, function(filter, key) {
16721         filters[key] = register(key, filter);
16722       });
16723       return filters;
16724     } else {
16725       return $provide.factory(name + suffix, factory);
16726     }
16727   }
16728   this.register = register;
16729
16730   this.$get = ['$injector', function($injector) {
16731     return function(name) {
16732       return $injector.get(name + suffix);
16733     };
16734   }];
16735
16736   ////////////////////////////////////////
16737
16738   /* global
16739     currencyFilter: false,
16740     dateFilter: false,
16741     filterFilter: false,
16742     jsonFilter: false,
16743     limitToFilter: false,
16744     lowercaseFilter: false,
16745     numberFilter: false,
16746     orderByFilter: false,
16747     uppercaseFilter: false,
16748   */
16749
16750   register('currency', currencyFilter);
16751   register('date', dateFilter);
16752   register('filter', filterFilter);
16753   register('json', jsonFilter);
16754   register('limitTo', limitToFilter);
16755   register('lowercase', lowercaseFilter);
16756   register('number', numberFilter);
16757   register('orderBy', orderByFilter);
16758   register('uppercase', uppercaseFilter);
16759 }
16760
16761 /**
16762  * @ngdoc filter
16763  * @name filter
16764  * @kind function
16765  *
16766  * @description
16767  * Selects a subset of items from `array` and returns it as a new array.
16768  *
16769  * @param {Array} array The source array.
16770  * @param {string|Object|function()} expression The predicate to be used for selecting items from
16771  *   `array`.
16772  *
16773  *   Can be one of:
16774  *
16775  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
16776  *     objects with string properties in `array` that match this string will be returned. This also
16777  *     applies to nested object properties.
16778  *     The predicate can be negated by prefixing the string with `!`.
16779  *
16780  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
16781  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
16782  *     which have property `name` containing "M" and property `phone` containing "1". A special
16783  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
16784  *     property of the object or its nested object properties. That's equivalent to the simple
16785  *     substring match with a `string` as described above. The predicate can be negated by prefixing
16786  *     the string with `!`.
16787  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
16788  *     not containing "M".
16789  *
16790  *     Note that a named property will match properties on the same level only, while the special
16791  *     `$` property will match properties on the same level or deeper. E.g. an array item like
16792  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
16793  *     **will** be matched by `{$: 'John'}`.
16794  *
16795  *   - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
16796  *     function is called for each element of `array`. The final result is an array of those
16797  *     elements that the predicate returned true for.
16798  *
16799  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
16800  *     determining if the expected value (from the filter expression) and actual value (from
16801  *     the object in the array) should be considered a match.
16802  *
16803  *   Can be one of:
16804  *
16805  *   - `function(actual, expected)`:
16806  *     The function will be given the object value and the predicate value to compare and
16807  *     should return true if both values should be considered equal.
16808  *
16809  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
16810  *     This is essentially strict comparison of expected and actual.
16811  *
16812  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
16813  *     insensitive way.
16814  *
16815  * @example
16816    <example>
16817      <file name="index.html">
16818        <div ng-init="friends = [{name:'John', phone:'555-1276'},
16819                                 {name:'Mary', phone:'800-BIG-MARY'},
16820                                 {name:'Mike', phone:'555-4321'},
16821                                 {name:'Adam', phone:'555-5678'},
16822                                 {name:'Julie', phone:'555-8765'},
16823                                 {name:'Juliette', phone:'555-5678'}]"></div>
16824
16825        Search: <input ng-model="searchText">
16826        <table id="searchTextResults">
16827          <tr><th>Name</th><th>Phone</th></tr>
16828          <tr ng-repeat="friend in friends | filter:searchText">
16829            <td>{{friend.name}}</td>
16830            <td>{{friend.phone}}</td>
16831          </tr>
16832        </table>
16833        <hr>
16834        Any: <input ng-model="search.$"> <br>
16835        Name only <input ng-model="search.name"><br>
16836        Phone only <input ng-model="search.phone"><br>
16837        Equality <input type="checkbox" ng-model="strict"><br>
16838        <table id="searchObjResults">
16839          <tr><th>Name</th><th>Phone</th></tr>
16840          <tr ng-repeat="friendObj in friends | filter:search:strict">
16841            <td>{{friendObj.name}}</td>
16842            <td>{{friendObj.phone}}</td>
16843          </tr>
16844        </table>
16845      </file>
16846      <file name="protractor.js" type="protractor">
16847        var expectFriendNames = function(expectedNames, key) {
16848          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
16849            arr.forEach(function(wd, i) {
16850              expect(wd.getText()).toMatch(expectedNames[i]);
16851            });
16852          });
16853        };
16854
16855        it('should search across all fields when filtering with a string', function() {
16856          var searchText = element(by.model('searchText'));
16857          searchText.clear();
16858          searchText.sendKeys('m');
16859          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
16860
16861          searchText.clear();
16862          searchText.sendKeys('76');
16863          expectFriendNames(['John', 'Julie'], 'friend');
16864        });
16865
16866        it('should search in specific fields when filtering with a predicate object', function() {
16867          var searchAny = element(by.model('search.$'));
16868          searchAny.clear();
16869          searchAny.sendKeys('i');
16870          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
16871        });
16872        it('should use a equal comparison when comparator is true', function() {
16873          var searchName = element(by.model('search.name'));
16874          var strict = element(by.model('strict'));
16875          searchName.clear();
16876          searchName.sendKeys('Julie');
16877          strict.click();
16878          expectFriendNames(['Julie'], 'friendObj');
16879        });
16880      </file>
16881    </example>
16882  */
16883 function filterFilter() {
16884   return function(array, expression, comparator) {
16885     if (!isArray(array)) return array;
16886
16887     var expressionType = (expression !== null) ? typeof expression : 'null';
16888     var predicateFn;
16889     var matchAgainstAnyProp;
16890
16891     switch (expressionType) {
16892       case 'function':
16893         predicateFn = expression;
16894         break;
16895       case 'boolean':
16896       case 'null':
16897       case 'number':
16898       case 'string':
16899         matchAgainstAnyProp = true;
16900         //jshint -W086
16901       case 'object':
16902         //jshint +W086
16903         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
16904         break;
16905       default:
16906         return array;
16907     }
16908
16909     return array.filter(predicateFn);
16910   };
16911 }
16912
16913 // Helper functions for `filterFilter`
16914 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
16915   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
16916   var predicateFn;
16917
16918   if (comparator === true) {
16919     comparator = equals;
16920   } else if (!isFunction(comparator)) {
16921     comparator = function(actual, expected) {
16922       if (isUndefined(actual)) {
16923         // No substring matching against `undefined`
16924         return false;
16925       }
16926       if ((actual === null) || (expected === null)) {
16927         // No substring matching against `null`; only match against `null`
16928         return actual === expected;
16929       }
16930       if (isObject(actual) || isObject(expected)) {
16931         // Prevent an object to be considered equal to a string like `'[object'`
16932         return false;
16933       }
16934
16935       actual = lowercase('' + actual);
16936       expected = lowercase('' + expected);
16937       return actual.indexOf(expected) !== -1;
16938     };
16939   }
16940
16941   predicateFn = function(item) {
16942     if (shouldMatchPrimitives && !isObject(item)) {
16943       return deepCompare(item, expression.$, comparator, false);
16944     }
16945     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
16946   };
16947
16948   return predicateFn;
16949 }
16950
16951 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
16952   var actualType = (actual !== null) ? typeof actual : 'null';
16953   var expectedType = (expected !== null) ? typeof expected : 'null';
16954
16955   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
16956     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
16957   } else if (isArray(actual)) {
16958     // In case `actual` is an array, consider it a match
16959     // if ANY of it's items matches `expected`
16960     return actual.some(function(item) {
16961       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
16962     });
16963   }
16964
16965   switch (actualType) {
16966     case 'object':
16967       var key;
16968       if (matchAgainstAnyProp) {
16969         for (key in actual) {
16970           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
16971             return true;
16972           }
16973         }
16974         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
16975       } else if (expectedType === 'object') {
16976         for (key in expected) {
16977           var expectedVal = expected[key];
16978           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
16979             continue;
16980           }
16981
16982           var matchAnyProperty = key === '$';
16983           var actualVal = matchAnyProperty ? actual : actual[key];
16984           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
16985             return false;
16986           }
16987         }
16988         return true;
16989       } else {
16990         return comparator(actual, expected);
16991       }
16992       break;
16993     case 'function':
16994       return false;
16995     default:
16996       return comparator(actual, expected);
16997   }
16998 }
16999
17000 /**
17001  * @ngdoc filter
17002  * @name currency
17003  * @kind function
17004  *
17005  * @description
17006  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
17007  * symbol for current locale is used.
17008  *
17009  * @param {number} amount Input to filter.
17010  * @param {string=} symbol Currency symbol or identifier to be displayed.
17011  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
17012  * @returns {string} Formatted number.
17013  *
17014  *
17015  * @example
17016    <example module="currencyExample">
17017      <file name="index.html">
17018        <script>
17019          angular.module('currencyExample', [])
17020            .controller('ExampleController', ['$scope', function($scope) {
17021              $scope.amount = 1234.56;
17022            }]);
17023        </script>
17024        <div ng-controller="ExampleController">
17025          <input type="number" ng-model="amount"> <br>
17026          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
17027          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
17028          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
17029        </div>
17030      </file>
17031      <file name="protractor.js" type="protractor">
17032        it('should init with 1234.56', function() {
17033          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
17034          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
17035          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
17036        });
17037        it('should update', function() {
17038          if (browser.params.browser == 'safari') {
17039            // Safari does not understand the minus key. See
17040            // https://github.com/angular/protractor/issues/481
17041            return;
17042          }
17043          element(by.model('amount')).clear();
17044          element(by.model('amount')).sendKeys('-1234');
17045          expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
17046          expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
17047          expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
17048        });
17049      </file>
17050    </example>
17051  */
17052 currencyFilter.$inject = ['$locale'];
17053 function currencyFilter($locale) {
17054   var formats = $locale.NUMBER_FORMATS;
17055   return function(amount, currencySymbol, fractionSize) {
17056     if (isUndefined(currencySymbol)) {
17057       currencySymbol = formats.CURRENCY_SYM;
17058     }
17059
17060     if (isUndefined(fractionSize)) {
17061       fractionSize = formats.PATTERNS[1].maxFrac;
17062     }
17063
17064     // if null or undefined pass it through
17065     return (amount == null)
17066         ? amount
17067         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
17068             replace(/\u00A4/g, currencySymbol);
17069   };
17070 }
17071
17072 /**
17073  * @ngdoc filter
17074  * @name number
17075  * @kind function
17076  *
17077  * @description
17078  * Formats a number as text.
17079  *
17080  * If the input is null or undefined, it will just be returned.
17081  * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
17082  * If the input is not a number an empty string is returned.
17083  *
17084  * @param {number|string} number Number to format.
17085  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
17086  * If this is not provided then the fraction size is computed from the current locale's number
17087  * formatting pattern. In the case of the default locale, it will be 3.
17088  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
17089  *
17090  * @example
17091    <example module="numberFilterExample">
17092      <file name="index.html">
17093        <script>
17094          angular.module('numberFilterExample', [])
17095            .controller('ExampleController', ['$scope', function($scope) {
17096              $scope.val = 1234.56789;
17097            }]);
17098        </script>
17099        <div ng-controller="ExampleController">
17100          Enter number: <input ng-model='val'><br>
17101          Default formatting: <span id='number-default'>{{val | number}}</span><br>
17102          No fractions: <span>{{val | number:0}}</span><br>
17103          Negative number: <span>{{-val | number:4}}</span>
17104        </div>
17105      </file>
17106      <file name="protractor.js" type="protractor">
17107        it('should format numbers', function() {
17108          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
17109          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
17110          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
17111        });
17112
17113        it('should update', function() {
17114          element(by.model('val')).clear();
17115          element(by.model('val')).sendKeys('3374.333');
17116          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
17117          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
17118          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
17119       });
17120      </file>
17121    </example>
17122  */
17123
17124
17125 numberFilter.$inject = ['$locale'];
17126 function numberFilter($locale) {
17127   var formats = $locale.NUMBER_FORMATS;
17128   return function(number, fractionSize) {
17129
17130     // if null or undefined pass it through
17131     return (number == null)
17132         ? number
17133         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
17134                        fractionSize);
17135   };
17136 }
17137
17138 var DECIMAL_SEP = '.';
17139 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
17140   if (!isFinite(number) || isObject(number)) return '';
17141
17142   var isNegative = number < 0;
17143   number = Math.abs(number);
17144   var numStr = number + '',
17145       formatedText = '',
17146       parts = [];
17147
17148   var hasExponent = false;
17149   if (numStr.indexOf('e') !== -1) {
17150     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
17151     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
17152       number = 0;
17153     } else {
17154       formatedText = numStr;
17155       hasExponent = true;
17156     }
17157   }
17158
17159   if (!hasExponent) {
17160     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
17161
17162     // determine fractionSize if it is not specified
17163     if (isUndefined(fractionSize)) {
17164       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
17165     }
17166
17167     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
17168     // inspired by:
17169     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
17170     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
17171
17172     var fraction = ('' + number).split(DECIMAL_SEP);
17173     var whole = fraction[0];
17174     fraction = fraction[1] || '';
17175
17176     var i, pos = 0,
17177         lgroup = pattern.lgSize,
17178         group = pattern.gSize;
17179
17180     if (whole.length >= (lgroup + group)) {
17181       pos = whole.length - lgroup;
17182       for (i = 0; i < pos; i++) {
17183         if ((pos - i) % group === 0 && i !== 0) {
17184           formatedText += groupSep;
17185         }
17186         formatedText += whole.charAt(i);
17187       }
17188     }
17189
17190     for (i = pos; i < whole.length; i++) {
17191       if ((whole.length - i) % lgroup === 0 && i !== 0) {
17192         formatedText += groupSep;
17193       }
17194       formatedText += whole.charAt(i);
17195     }
17196
17197     // format fraction part.
17198     while (fraction.length < fractionSize) {
17199       fraction += '0';
17200     }
17201
17202     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
17203   } else {
17204     if (fractionSize > 0 && number < 1) {
17205       formatedText = number.toFixed(fractionSize);
17206       number = parseFloat(formatedText);
17207     }
17208   }
17209
17210   if (number === 0) {
17211     isNegative = false;
17212   }
17213
17214   parts.push(isNegative ? pattern.negPre : pattern.posPre,
17215              formatedText,
17216              isNegative ? pattern.negSuf : pattern.posSuf);
17217   return parts.join('');
17218 }
17219
17220 function padNumber(num, digits, trim) {
17221   var neg = '';
17222   if (num < 0) {
17223     neg =  '-';
17224     num = -num;
17225   }
17226   num = '' + num;
17227   while (num.length < digits) num = '0' + num;
17228   if (trim)
17229     num = num.substr(num.length - digits);
17230   return neg + num;
17231 }
17232
17233
17234 function dateGetter(name, size, offset, trim) {
17235   offset = offset || 0;
17236   return function(date) {
17237     var value = date['get' + name]();
17238     if (offset > 0 || value > -offset)
17239       value += offset;
17240     if (value === 0 && offset == -12) value = 12;
17241     return padNumber(value, size, trim);
17242   };
17243 }
17244
17245 function dateStrGetter(name, shortForm) {
17246   return function(date, formats) {
17247     var value = date['get' + name]();
17248     var get = uppercase(shortForm ? ('SHORT' + name) : name);
17249
17250     return formats[get][value];
17251   };
17252 }
17253
17254 function timeZoneGetter(date) {
17255   var zone = -1 * date.getTimezoneOffset();
17256   var paddedZone = (zone >= 0) ? "+" : "";
17257
17258   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
17259                 padNumber(Math.abs(zone % 60), 2);
17260
17261   return paddedZone;
17262 }
17263
17264 function getFirstThursdayOfYear(year) {
17265     // 0 = index of January
17266     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
17267     // 4 = index of Thursday (+1 to account for 1st = 5)
17268     // 11 = index of *next* Thursday (+1 account for 1st = 12)
17269     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
17270 }
17271
17272 function getThursdayThisWeek(datetime) {
17273     return new Date(datetime.getFullYear(), datetime.getMonth(),
17274       // 4 = index of Thursday
17275       datetime.getDate() + (4 - datetime.getDay()));
17276 }
17277
17278 function weekGetter(size) {
17279    return function(date) {
17280       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
17281          thisThurs = getThursdayThisWeek(date);
17282
17283       var diff = +thisThurs - +firstThurs,
17284          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
17285
17286       return padNumber(result, size);
17287    };
17288 }
17289
17290 function ampmGetter(date, formats) {
17291   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
17292 }
17293
17294 function eraGetter(date, formats) {
17295   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
17296 }
17297
17298 function longEraGetter(date, formats) {
17299   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
17300 }
17301
17302 var DATE_FORMATS = {
17303   yyyy: dateGetter('FullYear', 4),
17304     yy: dateGetter('FullYear', 2, 0, true),
17305      y: dateGetter('FullYear', 1),
17306   MMMM: dateStrGetter('Month'),
17307    MMM: dateStrGetter('Month', true),
17308     MM: dateGetter('Month', 2, 1),
17309      M: dateGetter('Month', 1, 1),
17310     dd: dateGetter('Date', 2),
17311      d: dateGetter('Date', 1),
17312     HH: dateGetter('Hours', 2),
17313      H: dateGetter('Hours', 1),
17314     hh: dateGetter('Hours', 2, -12),
17315      h: dateGetter('Hours', 1, -12),
17316     mm: dateGetter('Minutes', 2),
17317      m: dateGetter('Minutes', 1),
17318     ss: dateGetter('Seconds', 2),
17319      s: dateGetter('Seconds', 1),
17320      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
17321      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
17322    sss: dateGetter('Milliseconds', 3),
17323   EEEE: dateStrGetter('Day'),
17324    EEE: dateStrGetter('Day', true),
17325      a: ampmGetter,
17326      Z: timeZoneGetter,
17327     ww: weekGetter(2),
17328      w: weekGetter(1),
17329      G: eraGetter,
17330      GG: eraGetter,
17331      GGG: eraGetter,
17332      GGGG: longEraGetter
17333 };
17334
17335 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
17336     NUMBER_STRING = /^\-?\d+$/;
17337
17338 /**
17339  * @ngdoc filter
17340  * @name date
17341  * @kind function
17342  *
17343  * @description
17344  *   Formats `date` to a string based on the requested `format`.
17345  *
17346  *   `format` string can be composed of the following elements:
17347  *
17348  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
17349  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
17350  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
17351  *   * `'MMMM'`: Month in year (January-December)
17352  *   * `'MMM'`: Month in year (Jan-Dec)
17353  *   * `'MM'`: Month in year, padded (01-12)
17354  *   * `'M'`: Month in year (1-12)
17355  *   * `'dd'`: Day in month, padded (01-31)
17356  *   * `'d'`: Day in month (1-31)
17357  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
17358  *   * `'EEE'`: Day in Week, (Sun-Sat)
17359  *   * `'HH'`: Hour in day, padded (00-23)
17360  *   * `'H'`: Hour in day (0-23)
17361  *   * `'hh'`: Hour in AM/PM, padded (01-12)
17362  *   * `'h'`: Hour in AM/PM, (1-12)
17363  *   * `'mm'`: Minute in hour, padded (00-59)
17364  *   * `'m'`: Minute in hour (0-59)
17365  *   * `'ss'`: Second in minute, padded (00-59)
17366  *   * `'s'`: Second in minute (0-59)
17367  *   * `'sss'`: Millisecond in second, padded (000-999)
17368  *   * `'a'`: AM/PM marker
17369  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
17370  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
17371  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
17372  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
17373  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
17374  *
17375  *   `format` string can also be one of the following predefined
17376  *   {@link guide/i18n localizable formats}:
17377  *
17378  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
17379  *     (e.g. Sep 3, 2010 12:05:08 PM)
17380  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
17381  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
17382  *     (e.g. Friday, September 3, 2010)
17383  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
17384  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
17385  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
17386  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
17387  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
17388  *
17389  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
17390  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
17391  *   (e.g. `"h 'o''clock'"`).
17392  *
17393  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
17394  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
17395  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
17396  *    specified in the string input, the time is considered to be in the local timezone.
17397  * @param {string=} format Formatting rules (see Description). If not specified,
17398  *    `mediumDate` is used.
17399  * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported.
17400  *    If not specified, the timezone of the browser will be used.
17401  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
17402  *
17403  * @example
17404    <example>
17405      <file name="index.html">
17406        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
17407            <span>{{1288323623006 | date:'medium'}}</span><br>
17408        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
17409           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
17410        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
17411           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
17412        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
17413           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
17414      </file>
17415      <file name="protractor.js" type="protractor">
17416        it('should format date', function() {
17417          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
17418             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
17419          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
17420             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
17421          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
17422             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
17423          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
17424             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
17425        });
17426      </file>
17427    </example>
17428  */
17429 dateFilter.$inject = ['$locale'];
17430 function dateFilter($locale) {
17431
17432
17433   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
17434                      // 1        2       3         4          5          6          7          8  9     10      11
17435   function jsonStringToDate(string) {
17436     var match;
17437     if (match = string.match(R_ISO8601_STR)) {
17438       var date = new Date(0),
17439           tzHour = 0,
17440           tzMin  = 0,
17441           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
17442           timeSetter = match[8] ? date.setUTCHours : date.setHours;
17443
17444       if (match[9]) {
17445         tzHour = int(match[9] + match[10]);
17446         tzMin = int(match[9] + match[11]);
17447       }
17448       dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
17449       var h = int(match[4] || 0) - tzHour;
17450       var m = int(match[5] || 0) - tzMin;
17451       var s = int(match[6] || 0);
17452       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
17453       timeSetter.call(date, h, m, s, ms);
17454       return date;
17455     }
17456     return string;
17457   }
17458
17459
17460   return function(date, format, timezone) {
17461     var text = '',
17462         parts = [],
17463         fn, match;
17464
17465     format = format || 'mediumDate';
17466     format = $locale.DATETIME_FORMATS[format] || format;
17467     if (isString(date)) {
17468       date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
17469     }
17470
17471     if (isNumber(date)) {
17472       date = new Date(date);
17473     }
17474
17475     if (!isDate(date)) {
17476       return date;
17477     }
17478
17479     while (format) {
17480       match = DATE_FORMATS_SPLIT.exec(format);
17481       if (match) {
17482         parts = concat(parts, match, 1);
17483         format = parts.pop();
17484       } else {
17485         parts.push(format);
17486         format = null;
17487       }
17488     }
17489
17490     if (timezone && timezone === 'UTC') {
17491       date = new Date(date.getTime());
17492       date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
17493     }
17494     forEach(parts, function(value) {
17495       fn = DATE_FORMATS[value];
17496       text += fn ? fn(date, $locale.DATETIME_FORMATS)
17497                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
17498     });
17499
17500     return text;
17501   };
17502 }
17503
17504
17505 /**
17506  * @ngdoc filter
17507  * @name json
17508  * @kind function
17509  *
17510  * @description
17511  *   Allows you to convert a JavaScript object into JSON string.
17512  *
17513  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
17514  *   the binding is automatically converted to JSON.
17515  *
17516  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
17517  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
17518  * @returns {string} JSON string.
17519  *
17520  *
17521  * @example
17522    <example>
17523      <file name="index.html">
17524        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
17525        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
17526      </file>
17527      <file name="protractor.js" type="protractor">
17528        it('should jsonify filtered objects', function() {
17529          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
17530          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
17531        });
17532      </file>
17533    </example>
17534  *
17535  */
17536 function jsonFilter() {
17537   return function(object, spacing) {
17538     if (isUndefined(spacing)) {
17539         spacing = 2;
17540     }
17541     return toJson(object, spacing);
17542   };
17543 }
17544
17545
17546 /**
17547  * @ngdoc filter
17548  * @name lowercase
17549  * @kind function
17550  * @description
17551  * Converts string to lowercase.
17552  * @see angular.lowercase
17553  */
17554 var lowercaseFilter = valueFn(lowercase);
17555
17556
17557 /**
17558  * @ngdoc filter
17559  * @name uppercase
17560  * @kind function
17561  * @description
17562  * Converts string to uppercase.
17563  * @see angular.uppercase
17564  */
17565 var uppercaseFilter = valueFn(uppercase);
17566
17567 /**
17568  * @ngdoc filter
17569  * @name limitTo
17570  * @kind function
17571  *
17572  * @description
17573  * Creates a new array or string containing only a specified number of elements. The elements
17574  * are taken from either the beginning or the end of the source array, string or number, as specified by
17575  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
17576  * converted to a string.
17577  *
17578  * @param {Array|string|number} input Source array, string or number to be limited.
17579  * @param {string|number} limit The length of the returned array or string. If the `limit` number
17580  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
17581  *     If the number is negative, `limit` number  of items from the end of the source array/string
17582  *     are copied. The `limit` will be trimmed if it exceeds `array.length`
17583  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
17584  *     had less than `limit` elements.
17585  *
17586  * @example
17587    <example module="limitToExample">
17588      <file name="index.html">
17589        <script>
17590          angular.module('limitToExample', [])
17591            .controller('ExampleController', ['$scope', function($scope) {
17592              $scope.numbers = [1,2,3,4,5,6,7,8,9];
17593              $scope.letters = "abcdefghi";
17594              $scope.longNumber = 2345432342;
17595              $scope.numLimit = 3;
17596              $scope.letterLimit = 3;
17597              $scope.longNumberLimit = 3;
17598            }]);
17599        </script>
17600        <div ng-controller="ExampleController">
17601          Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
17602          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
17603          Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
17604          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
17605          Limit {{longNumber}} to: <input type="number" step="1" ng-model="longNumberLimit">
17606          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
17607        </div>
17608      </file>
17609      <file name="protractor.js" type="protractor">
17610        var numLimitInput = element(by.model('numLimit'));
17611        var letterLimitInput = element(by.model('letterLimit'));
17612        var longNumberLimitInput = element(by.model('longNumberLimit'));
17613        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
17614        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
17615        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
17616
17617        it('should limit the number array to first three items', function() {
17618          expect(numLimitInput.getAttribute('value')).toBe('3');
17619          expect(letterLimitInput.getAttribute('value')).toBe('3');
17620          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
17621          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
17622          expect(limitedLetters.getText()).toEqual('Output letters: abc');
17623          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
17624        });
17625
17626        // There is a bug in safari and protractor that doesn't like the minus key
17627        // it('should update the output when -3 is entered', function() {
17628        //   numLimitInput.clear();
17629        //   numLimitInput.sendKeys('-3');
17630        //   letterLimitInput.clear();
17631        //   letterLimitInput.sendKeys('-3');
17632        //   longNumberLimitInput.clear();
17633        //   longNumberLimitInput.sendKeys('-3');
17634        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
17635        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
17636        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
17637        // });
17638
17639        it('should not exceed the maximum size of input array', function() {
17640          numLimitInput.clear();
17641          numLimitInput.sendKeys('100');
17642          letterLimitInput.clear();
17643          letterLimitInput.sendKeys('100');
17644          longNumberLimitInput.clear();
17645          longNumberLimitInput.sendKeys('100');
17646          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
17647          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
17648          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
17649        });
17650      </file>
17651    </example>
17652 */
17653 function limitToFilter() {
17654   return function(input, limit) {
17655     if (isNumber(input)) input = input.toString();
17656     if (!isArray(input) && !isString(input)) return input;
17657
17658     if (Math.abs(Number(limit)) === Infinity) {
17659       limit = Number(limit);
17660     } else {
17661       limit = int(limit);
17662     }
17663
17664     //NaN check on limit
17665     if (limit) {
17666       return limit > 0 ? input.slice(0, limit) : input.slice(limit);
17667     } else {
17668       return isString(input) ? "" : [];
17669     }
17670   };
17671 }
17672
17673 /**
17674  * @ngdoc filter
17675  * @name orderBy
17676  * @kind function
17677  *
17678  * @description
17679  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
17680  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
17681  * correctly, make sure they are actually being saved as numbers and not strings.
17682  *
17683  * @param {Array} array The array to sort.
17684  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
17685  *    used by the comparator to determine the order of elements.
17686  *
17687  *    Can be one of:
17688  *
17689  *    - `function`: Getter function. The result of this function will be sorted using the
17690  *      `<`, `===`, `>` operator.
17691  *    - `string`: An Angular expression. The result of this expression is used to compare elements
17692  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
17693  *      3 first characters of a property called `name`). The result of a constant expression
17694  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
17695  *      to sort object by the value of their `special name` property). An expression can be
17696  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
17697  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
17698  *      element itself is used to compare where sorting.
17699  *    - `Array`: An array of function or string predicates. The first predicate in the array
17700  *      is used for sorting, but when two items are equivalent, the next predicate is used.
17701  *
17702  *    If the predicate is missing or empty then it defaults to `'+'`.
17703  *
17704  * @param {boolean=} reverse Reverse the order of the array.
17705  * @returns {Array} Sorted copy of the source array.
17706  *
17707  *
17708  * @example
17709  * The example below demonstrates a simple ngRepeat, where the data is sorted
17710  * by age in descending order (predicate is set to `'-age'`).
17711  * `reverse` is not set, which means it defaults to `false`.
17712    <example module="orderByExample">
17713      <file name="index.html">
17714        <script>
17715          angular.module('orderByExample', [])
17716            .controller('ExampleController', ['$scope', function($scope) {
17717              $scope.friends =
17718                  [{name:'John', phone:'555-1212', age:10},
17719                   {name:'Mary', phone:'555-9876', age:19},
17720                   {name:'Mike', phone:'555-4321', age:21},
17721                   {name:'Adam', phone:'555-5678', age:35},
17722                   {name:'Julie', phone:'555-8765', age:29}];
17723            }]);
17724        </script>
17725        <div ng-controller="ExampleController">
17726          <table class="friend">
17727            <tr>
17728              <th>Name</th>
17729              <th>Phone Number</th>
17730              <th>Age</th>
17731            </tr>
17732            <tr ng-repeat="friend in friends | orderBy:'-age'">
17733              <td>{{friend.name}}</td>
17734              <td>{{friend.phone}}</td>
17735              <td>{{friend.age}}</td>
17736            </tr>
17737          </table>
17738        </div>
17739      </file>
17740    </example>
17741  *
17742  * The predicate and reverse parameters can be controlled dynamically through scope properties,
17743  * as shown in the next example.
17744  * @example
17745    <example module="orderByExample">
17746      <file name="index.html">
17747        <script>
17748          angular.module('orderByExample', [])
17749            .controller('ExampleController', ['$scope', function($scope) {
17750              $scope.friends =
17751                  [{name:'John', phone:'555-1212', age:10},
17752                   {name:'Mary', phone:'555-9876', age:19},
17753                   {name:'Mike', phone:'555-4321', age:21},
17754                   {name:'Adam', phone:'555-5678', age:35},
17755                   {name:'Julie', phone:'555-8765', age:29}];
17756              $scope.predicate = '-age';
17757            }]);
17758        </script>
17759        <div ng-controller="ExampleController">
17760          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
17761          <hr/>
17762          [ <a href="" ng-click="predicate=''">unsorted</a> ]
17763          <table class="friend">
17764            <tr>
17765              <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
17766                  (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
17767              <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
17768              <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
17769            </tr>
17770            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
17771              <td>{{friend.name}}</td>
17772              <td>{{friend.phone}}</td>
17773              <td>{{friend.age}}</td>
17774            </tr>
17775          </table>
17776        </div>
17777      </file>
17778    </example>
17779  *
17780  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
17781  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
17782  * desired parameters.
17783  *
17784  * Example:
17785  *
17786  * @example
17787   <example module="orderByExample">
17788     <file name="index.html">
17789       <div ng-controller="ExampleController">
17790         <table class="friend">
17791           <tr>
17792             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
17793               (<a href="" ng-click="order('-name',false)">^</a>)</th>
17794             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
17795             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
17796           </tr>
17797           <tr ng-repeat="friend in friends">
17798             <td>{{friend.name}}</td>
17799             <td>{{friend.phone}}</td>
17800             <td>{{friend.age}}</td>
17801           </tr>
17802         </table>
17803       </div>
17804     </file>
17805
17806     <file name="script.js">
17807       angular.module('orderByExample', [])
17808         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
17809           var orderBy = $filter('orderBy');
17810           $scope.friends = [
17811             { name: 'John',    phone: '555-1212',    age: 10 },
17812             { name: 'Mary',    phone: '555-9876',    age: 19 },
17813             { name: 'Mike',    phone: '555-4321',    age: 21 },
17814             { name: 'Adam',    phone: '555-5678',    age: 35 },
17815             { name: 'Julie',   phone: '555-8765',    age: 29 }
17816           ];
17817           $scope.order = function(predicate, reverse) {
17818             $scope.friends = orderBy($scope.friends, predicate, reverse);
17819           };
17820           $scope.order('-age',false);
17821         }]);
17822     </file>
17823 </example>
17824  */
17825 orderByFilter.$inject = ['$parse'];
17826 function orderByFilter($parse) {
17827   return function(array, sortPredicate, reverseOrder) {
17828     if (!(isArrayLike(array))) return array;
17829     sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
17830     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
17831     sortPredicate = sortPredicate.map(function(predicate) {
17832       var descending = false, get = predicate || identity;
17833       if (isString(predicate)) {
17834         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
17835           descending = predicate.charAt(0) == '-';
17836           predicate = predicate.substring(1);
17837         }
17838         if (predicate === '') {
17839           // Effectively no predicate was passed so we compare identity
17840           return reverseComparator(compare, descending);
17841         }
17842         get = $parse(predicate);
17843         if (get.constant) {
17844           var key = get();
17845           return reverseComparator(function(a, b) {
17846             return compare(a[key], b[key]);
17847           }, descending);
17848         }
17849       }
17850       return reverseComparator(function(a, b) {
17851         return compare(get(a),get(b));
17852       }, descending);
17853     });
17854     return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
17855
17856     function comparator(o1, o2) {
17857       for (var i = 0; i < sortPredicate.length; i++) {
17858         var comp = sortPredicate[i](o1, o2);
17859         if (comp !== 0) return comp;
17860       }
17861       return 0;
17862     }
17863     function reverseComparator(comp, descending) {
17864       return descending
17865           ? function(a, b) {return comp(b,a);}
17866           : comp;
17867     }
17868
17869     function isPrimitive(value) {
17870       switch (typeof value) {
17871         case 'number': /* falls through */
17872         case 'boolean': /* falls through */
17873         case 'string':
17874           return true;
17875         default:
17876           return false;
17877       }
17878     }
17879
17880     function objectToString(value) {
17881       if (value === null) return 'null';
17882       if (typeof value.valueOf === 'function') {
17883         value = value.valueOf();
17884         if (isPrimitive(value)) return value;
17885       }
17886       if (typeof value.toString === 'function') {
17887         value = value.toString();
17888         if (isPrimitive(value)) return value;
17889       }
17890       return '';
17891     }
17892
17893     function compare(v1, v2) {
17894       var t1 = typeof v1;
17895       var t2 = typeof v2;
17896       if (t1 === t2 && t1 === "object") {
17897         v1 = objectToString(v1);
17898         v2 = objectToString(v2);
17899       }
17900       if (t1 === t2) {
17901         if (t1 === "string") {
17902            v1 = v1.toLowerCase();
17903            v2 = v2.toLowerCase();
17904         }
17905         if (v1 === v2) return 0;
17906         return v1 < v2 ? -1 : 1;
17907       } else {
17908         return t1 < t2 ? -1 : 1;
17909       }
17910     }
17911   };
17912 }
17913
17914 function ngDirective(directive) {
17915   if (isFunction(directive)) {
17916     directive = {
17917       link: directive
17918     };
17919   }
17920   directive.restrict = directive.restrict || 'AC';
17921   return valueFn(directive);
17922 }
17923
17924 /**
17925  * @ngdoc directive
17926  * @name a
17927  * @restrict E
17928  *
17929  * @description
17930  * Modifies the default behavior of the html A tag so that the default action is prevented when
17931  * the href attribute is empty.
17932  *
17933  * This change permits the easy creation of action links with the `ngClick` directive
17934  * without changing the location or causing page reloads, e.g.:
17935  * `<a href="" ng-click="list.addItem()">Add Item</a>`
17936  */
17937 var htmlAnchorDirective = valueFn({
17938   restrict: 'E',
17939   compile: function(element, attr) {
17940     if (!attr.href && !attr.xlinkHref && !attr.name) {
17941       return function(scope, element) {
17942         // If the linked element is not an anchor tag anymore, do nothing
17943         if (element[0].nodeName.toLowerCase() !== 'a') return;
17944
17945         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
17946         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
17947                    'xlink:href' : 'href';
17948         element.on('click', function(event) {
17949           // if we have no href url, then don't navigate anywhere.
17950           if (!element.attr(href)) {
17951             event.preventDefault();
17952           }
17953         });
17954       };
17955     }
17956   }
17957 });
17958
17959 /**
17960  * @ngdoc directive
17961  * @name ngHref
17962  * @restrict A
17963  * @priority 99
17964  *
17965  * @description
17966  * Using Angular markup like `{{hash}}` in an href attribute will
17967  * make the link go to the wrong URL if the user clicks it before
17968  * Angular has a chance to replace the `{{hash}}` markup with its
17969  * value. Until Angular replaces the markup the link will be broken
17970  * and will most likely return a 404 error. The `ngHref` directive
17971  * solves this problem.
17972  *
17973  * The wrong way to write it:
17974  * ```html
17975  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17976  * ```
17977  *
17978  * The correct way to write it:
17979  * ```html
17980  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17981  * ```
17982  *
17983  * @element A
17984  * @param {template} ngHref any string which can contain `{{}}` markup.
17985  *
17986  * @example
17987  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
17988  * in links and their different behaviors:
17989     <example>
17990       <file name="index.html">
17991         <input ng-model="value" /><br />
17992         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
17993         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
17994         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
17995         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
17996         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
17997         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
17998       </file>
17999       <file name="protractor.js" type="protractor">
18000         it('should execute ng-click but not reload when href without value', function() {
18001           element(by.id('link-1')).click();
18002           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
18003           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
18004         });
18005
18006         it('should execute ng-click but not reload when href empty string', function() {
18007           element(by.id('link-2')).click();
18008           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
18009           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
18010         });
18011
18012         it('should execute ng-click and change url when ng-href specified', function() {
18013           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
18014
18015           element(by.id('link-3')).click();
18016
18017           // At this point, we navigate away from an Angular page, so we need
18018           // to use browser.driver to get the base webdriver.
18019
18020           browser.wait(function() {
18021             return browser.driver.getCurrentUrl().then(function(url) {
18022               return url.match(/\/123$/);
18023             });
18024           }, 5000, 'page should navigate to /123');
18025         });
18026
18027         xit('should execute ng-click but not reload when href empty string and name specified', function() {
18028           element(by.id('link-4')).click();
18029           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
18030           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
18031         });
18032
18033         it('should execute ng-click but not reload when no href but name specified', function() {
18034           element(by.id('link-5')).click();
18035           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
18036           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
18037         });
18038
18039         it('should only change url when only ng-href', function() {
18040           element(by.model('value')).clear();
18041           element(by.model('value')).sendKeys('6');
18042           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
18043
18044           element(by.id('link-6')).click();
18045
18046           // At this point, we navigate away from an Angular page, so we need
18047           // to use browser.driver to get the base webdriver.
18048           browser.wait(function() {
18049             return browser.driver.getCurrentUrl().then(function(url) {
18050               return url.match(/\/6$/);
18051             });
18052           }, 5000, 'page should navigate to /6');
18053         });
18054       </file>
18055     </example>
18056  */
18057
18058 /**
18059  * @ngdoc directive
18060  * @name ngSrc
18061  * @restrict A
18062  * @priority 99
18063  *
18064  * @description
18065  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
18066  * work right: The browser will fetch from the URL with the literal
18067  * text `{{hash}}` until Angular replaces the expression inside
18068  * `{{hash}}`. The `ngSrc` directive solves this problem.
18069  *
18070  * The buggy way to write it:
18071  * ```html
18072  * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
18073  * ```
18074  *
18075  * The correct way to write it:
18076  * ```html
18077  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
18078  * ```
18079  *
18080  * @element IMG
18081  * @param {template} ngSrc any string which can contain `{{}}` markup.
18082  */
18083
18084 /**
18085  * @ngdoc directive
18086  * @name ngSrcset
18087  * @restrict A
18088  * @priority 99
18089  *
18090  * @description
18091  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
18092  * work right: The browser will fetch from the URL with the literal
18093  * text `{{hash}}` until Angular replaces the expression inside
18094  * `{{hash}}`. The `ngSrcset` directive solves this problem.
18095  *
18096  * The buggy way to write it:
18097  * ```html
18098  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
18099  * ```
18100  *
18101  * The correct way to write it:
18102  * ```html
18103  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
18104  * ```
18105  *
18106  * @element IMG
18107  * @param {template} ngSrcset any string which can contain `{{}}` markup.
18108  */
18109
18110 /**
18111  * @ngdoc directive
18112  * @name ngDisabled
18113  * @restrict A
18114  * @priority 100
18115  *
18116  * @description
18117  *
18118  * This directive sets the `disabled` attribute on the element if the
18119  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
18120  *
18121  * A special directive is necessary because we cannot use interpolation inside the `disabled`
18122  * attribute.  The following example would make the button enabled on Chrome/Firefox
18123  * but not on older IEs:
18124  *
18125  * ```html
18126  * <!-- See below for an example of ng-disabled being used correctly -->
18127  * <div ng-init="isDisabled = false">
18128  *  <button disabled="{{isDisabled}}">Disabled</button>
18129  * </div>
18130  * ```
18131  *
18132  * This is because the HTML specification does not require browsers to preserve the values of
18133  * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
18134  * If we put an Angular interpolation expression into such an attribute then the
18135  * binding information would be lost when the browser removes the attribute.
18136  *
18137  * @example
18138     <example>
18139       <file name="index.html">
18140         Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
18141         <button ng-model="button" ng-disabled="checked">Button</button>
18142       </file>
18143       <file name="protractor.js" type="protractor">
18144         it('should toggle button', function() {
18145           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
18146           element(by.model('checked')).click();
18147           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
18148         });
18149       </file>
18150     </example>
18151  *
18152  * @element INPUT
18153  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
18154  *     then the `disabled` attribute will be set on the element
18155  */
18156
18157
18158 /**
18159  * @ngdoc directive
18160  * @name ngChecked
18161  * @restrict A
18162  * @priority 100
18163  *
18164  * @description
18165  * The HTML specification does not require browsers to preserve the values of boolean attributes
18166  * such as checked. (Their presence means true and their absence means false.)
18167  * If we put an Angular interpolation expression into such an attribute then the
18168  * binding information would be lost when the browser removes the attribute.
18169  * The `ngChecked` directive solves this problem for the `checked` attribute.
18170  * This complementary directive is not removed by the browser and so provides
18171  * a permanent reliable place to store the binding information.
18172  * @example
18173     <example>
18174       <file name="index.html">
18175         Check me to check both: <input type="checkbox" ng-model="master"><br/>
18176         <input id="checkSlave" type="checkbox" ng-checked="master">
18177       </file>
18178       <file name="protractor.js" type="protractor">
18179         it('should check both checkBoxes', function() {
18180           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
18181           element(by.model('master')).click();
18182           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
18183         });
18184       </file>
18185     </example>
18186  *
18187  * @element INPUT
18188  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
18189  *     then special attribute "checked" will be set on the element
18190  */
18191
18192
18193 /**
18194  * @ngdoc directive
18195  * @name ngReadonly
18196  * @restrict A
18197  * @priority 100
18198  *
18199  * @description
18200  * The HTML specification does not require browsers to preserve the values of boolean attributes
18201  * such as readonly. (Their presence means true and their absence means false.)
18202  * If we put an Angular interpolation expression into such an attribute then the
18203  * binding information would be lost when the browser removes the attribute.
18204  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
18205  * This complementary directive is not removed by the browser and so provides
18206  * a permanent reliable place to store the binding information.
18207  * @example
18208     <example>
18209       <file name="index.html">
18210         Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
18211         <input type="text" ng-readonly="checked" value="I'm Angular"/>
18212       </file>
18213       <file name="protractor.js" type="protractor">
18214         it('should toggle readonly attr', function() {
18215           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
18216           element(by.model('checked')).click();
18217           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
18218         });
18219       </file>
18220     </example>
18221  *
18222  * @element INPUT
18223  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
18224  *     then special attribute "readonly" will be set on the element
18225  */
18226
18227
18228 /**
18229  * @ngdoc directive
18230  * @name ngSelected
18231  * @restrict A
18232  * @priority 100
18233  *
18234  * @description
18235  * The HTML specification does not require browsers to preserve the values of boolean attributes
18236  * such as selected. (Their presence means true and their absence means false.)
18237  * If we put an Angular interpolation expression into such an attribute then the
18238  * binding information would be lost when the browser removes the attribute.
18239  * The `ngSelected` directive solves this problem for the `selected` attribute.
18240  * This complementary directive is not removed by the browser and so provides
18241  * a permanent reliable place to store the binding information.
18242  *
18243  * @example
18244     <example>
18245       <file name="index.html">
18246         Check me to select: <input type="checkbox" ng-model="selected"><br/>
18247         <select>
18248           <option>Hello!</option>
18249           <option id="greet" ng-selected="selected">Greetings!</option>
18250         </select>
18251       </file>
18252       <file name="protractor.js" type="protractor">
18253         it('should select Greetings!', function() {
18254           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
18255           element(by.model('selected')).click();
18256           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
18257         });
18258       </file>
18259     </example>
18260  *
18261  * @element OPTION
18262  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
18263  *     then special attribute "selected" will be set on the element
18264  */
18265
18266 /**
18267  * @ngdoc directive
18268  * @name ngOpen
18269  * @restrict A
18270  * @priority 100
18271  *
18272  * @description
18273  * The HTML specification does not require browsers to preserve the values of boolean attributes
18274  * such as open. (Their presence means true and their absence means false.)
18275  * If we put an Angular interpolation expression into such an attribute then the
18276  * binding information would be lost when the browser removes the attribute.
18277  * The `ngOpen` directive solves this problem for the `open` attribute.
18278  * This complementary directive is not removed by the browser and so provides
18279  * a permanent reliable place to store the binding information.
18280  * @example
18281      <example>
18282        <file name="index.html">
18283          Check me check multiple: <input type="checkbox" ng-model="open"><br/>
18284          <details id="details" ng-open="open">
18285             <summary>Show/Hide me</summary>
18286          </details>
18287        </file>
18288        <file name="protractor.js" type="protractor">
18289          it('should toggle open', function() {
18290            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
18291            element(by.model('open')).click();
18292            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
18293          });
18294        </file>
18295      </example>
18296  *
18297  * @element DETAILS
18298  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
18299  *     then special attribute "open" will be set on the element
18300  */
18301
18302 var ngAttributeAliasDirectives = {};
18303
18304
18305 // boolean attrs are evaluated
18306 forEach(BOOLEAN_ATTR, function(propName, attrName) {
18307   // binding to multiple is not supported
18308   if (propName == "multiple") return;
18309
18310   var normalized = directiveNormalize('ng-' + attrName);
18311   ngAttributeAliasDirectives[normalized] = function() {
18312     return {
18313       restrict: 'A',
18314       priority: 100,
18315       link: function(scope, element, attr) {
18316         scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
18317           attr.$set(attrName, !!value);
18318         });
18319       }
18320     };
18321   };
18322 });
18323
18324 // aliased input attrs are evaluated
18325 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
18326   ngAttributeAliasDirectives[ngAttr] = function() {
18327     return {
18328       priority: 100,
18329       link: function(scope, element, attr) {
18330         //special case ngPattern when a literal regular expression value
18331         //is used as the expression (this way we don't have to watch anything).
18332         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
18333           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
18334           if (match) {
18335             attr.$set("ngPattern", new RegExp(match[1], match[2]));
18336             return;
18337           }
18338         }
18339
18340         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
18341           attr.$set(ngAttr, value);
18342         });
18343       }
18344     };
18345   };
18346 });
18347
18348 // ng-src, ng-srcset, ng-href are interpolated
18349 forEach(['src', 'srcset', 'href'], function(attrName) {
18350   var normalized = directiveNormalize('ng-' + attrName);
18351   ngAttributeAliasDirectives[normalized] = function() {
18352     return {
18353       priority: 99, // it needs to run after the attributes are interpolated
18354       link: function(scope, element, attr) {
18355         var propName = attrName,
18356             name = attrName;
18357
18358         if (attrName === 'href' &&
18359             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
18360           name = 'xlinkHref';
18361           attr.$attr[name] = 'xlink:href';
18362           propName = null;
18363         }
18364
18365         attr.$observe(normalized, function(value) {
18366           if (!value) {
18367             if (attrName === 'href') {
18368               attr.$set(name, null);
18369             }
18370             return;
18371           }
18372
18373           attr.$set(name, value);
18374
18375           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
18376           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
18377           // to set the property as well to achieve the desired effect.
18378           // we use attr[attrName] value since $set can sanitize the url.
18379           if (msie && propName) element.prop(propName, attr[name]);
18380         });
18381       }
18382     };
18383   };
18384 });
18385
18386 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
18387  */
18388 var nullFormCtrl = {
18389   $addControl: noop,
18390   $$renameControl: nullFormRenameControl,
18391   $removeControl: noop,
18392   $setValidity: noop,
18393   $setDirty: noop,
18394   $setPristine: noop,
18395   $setSubmitted: noop
18396 },
18397 SUBMITTED_CLASS = 'ng-submitted';
18398
18399 function nullFormRenameControl(control, name) {
18400   control.$name = name;
18401 }
18402
18403 /**
18404  * @ngdoc type
18405  * @name form.FormController
18406  *
18407  * @property {boolean} $pristine True if user has not interacted with the form yet.
18408  * @property {boolean} $dirty True if user has already interacted with the form.
18409  * @property {boolean} $valid True if all of the containing forms and controls are valid.
18410  * @property {boolean} $invalid True if at least one containing control or form is invalid.
18411  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
18412  *
18413  * @property {Object} $error Is an object hash, containing references to controls or
18414  *  forms with failing validators, where:
18415  *
18416  *  - keys are validation tokens (error names),
18417  *  - values are arrays of controls or forms that have a failing validator for given error name.
18418  *
18419  *  Built-in validation tokens:
18420  *
18421  *  - `email`
18422  *  - `max`
18423  *  - `maxlength`
18424  *  - `min`
18425  *  - `minlength`
18426  *  - `number`
18427  *  - `pattern`
18428  *  - `required`
18429  *  - `url`
18430  *  - `date`
18431  *  - `datetimelocal`
18432  *  - `time`
18433  *  - `week`
18434  *  - `month`
18435  *
18436  * @description
18437  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
18438  * such as being valid/invalid or dirty/pristine.
18439  *
18440  * Each {@link ng.directive:form form} directive creates an instance
18441  * of `FormController`.
18442  *
18443  */
18444 //asks for $scope to fool the BC controller module
18445 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
18446 function FormController(element, attrs, $scope, $animate, $interpolate) {
18447   var form = this,
18448       controls = [];
18449
18450   var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
18451
18452   // init state
18453   form.$error = {};
18454   form.$$success = {};
18455   form.$pending = undefined;
18456   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
18457   form.$dirty = false;
18458   form.$pristine = true;
18459   form.$valid = true;
18460   form.$invalid = false;
18461   form.$submitted = false;
18462
18463   parentForm.$addControl(form);
18464
18465   /**
18466    * @ngdoc method
18467    * @name form.FormController#$rollbackViewValue
18468    *
18469    * @description
18470    * Rollback all form controls pending updates to the `$modelValue`.
18471    *
18472    * Updates may be pending by a debounced event or because the input is waiting for a some future
18473    * event defined in `ng-model-options`. This method is typically needed by the reset button of
18474    * a form that uses `ng-model-options` to pend updates.
18475    */
18476   form.$rollbackViewValue = function() {
18477     forEach(controls, function(control) {
18478       control.$rollbackViewValue();
18479     });
18480   };
18481
18482   /**
18483    * @ngdoc method
18484    * @name form.FormController#$commitViewValue
18485    *
18486    * @description
18487    * Commit all form controls pending updates to the `$modelValue`.
18488    *
18489    * Updates may be pending by a debounced event or because the input is waiting for a some future
18490    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
18491    * usually handles calling this in response to input events.
18492    */
18493   form.$commitViewValue = function() {
18494     forEach(controls, function(control) {
18495       control.$commitViewValue();
18496     });
18497   };
18498
18499   /**
18500    * @ngdoc method
18501    * @name form.FormController#$addControl
18502    *
18503    * @description
18504    * Register a control with the form.
18505    *
18506    * Input elements using ngModelController do this automatically when they are linked.
18507    */
18508   form.$addControl = function(control) {
18509     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
18510     // and not added to the scope.  Now we throw an error.
18511     assertNotHasOwnProperty(control.$name, 'input');
18512     controls.push(control);
18513
18514     if (control.$name) {
18515       form[control.$name] = control;
18516     }
18517   };
18518
18519   // Private API: rename a form control
18520   form.$$renameControl = function(control, newName) {
18521     var oldName = control.$name;
18522
18523     if (form[oldName] === control) {
18524       delete form[oldName];
18525     }
18526     form[newName] = control;
18527     control.$name = newName;
18528   };
18529
18530   /**
18531    * @ngdoc method
18532    * @name form.FormController#$removeControl
18533    *
18534    * @description
18535    * Deregister a control from the form.
18536    *
18537    * Input elements using ngModelController do this automatically when they are destroyed.
18538    */
18539   form.$removeControl = function(control) {
18540     if (control.$name && form[control.$name] === control) {
18541       delete form[control.$name];
18542     }
18543     forEach(form.$pending, function(value, name) {
18544       form.$setValidity(name, null, control);
18545     });
18546     forEach(form.$error, function(value, name) {
18547       form.$setValidity(name, null, control);
18548     });
18549     forEach(form.$$success, function(value, name) {
18550       form.$setValidity(name, null, control);
18551     });
18552
18553     arrayRemove(controls, control);
18554   };
18555
18556
18557   /**
18558    * @ngdoc method
18559    * @name form.FormController#$setValidity
18560    *
18561    * @description
18562    * Sets the validity of a form control.
18563    *
18564    * This method will also propagate to parent forms.
18565    */
18566   addSetValidityMethod({
18567     ctrl: this,
18568     $element: element,
18569     set: function(object, property, controller) {
18570       var list = object[property];
18571       if (!list) {
18572         object[property] = [controller];
18573       } else {
18574         var index = list.indexOf(controller);
18575         if (index === -1) {
18576           list.push(controller);
18577         }
18578       }
18579     },
18580     unset: function(object, property, controller) {
18581       var list = object[property];
18582       if (!list) {
18583         return;
18584       }
18585       arrayRemove(list, controller);
18586       if (list.length === 0) {
18587         delete object[property];
18588       }
18589     },
18590     parentForm: parentForm,
18591     $animate: $animate
18592   });
18593
18594   /**
18595    * @ngdoc method
18596    * @name form.FormController#$setDirty
18597    *
18598    * @description
18599    * Sets the form to a dirty state.
18600    *
18601    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
18602    * state (ng-dirty class). This method will also propagate to parent forms.
18603    */
18604   form.$setDirty = function() {
18605     $animate.removeClass(element, PRISTINE_CLASS);
18606     $animate.addClass(element, DIRTY_CLASS);
18607     form.$dirty = true;
18608     form.$pristine = false;
18609     parentForm.$setDirty();
18610   };
18611
18612   /**
18613    * @ngdoc method
18614    * @name form.FormController#$setPristine
18615    *
18616    * @description
18617    * Sets the form to its pristine state.
18618    *
18619    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
18620    * state (ng-pristine class). This method will also propagate to all the controls contained
18621    * in this form.
18622    *
18623    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
18624    * saving or resetting it.
18625    */
18626   form.$setPristine = function() {
18627     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
18628     form.$dirty = false;
18629     form.$pristine = true;
18630     form.$submitted = false;
18631     forEach(controls, function(control) {
18632       control.$setPristine();
18633     });
18634   };
18635
18636   /**
18637    * @ngdoc method
18638    * @name form.FormController#$setUntouched
18639    *
18640    * @description
18641    * Sets the form to its untouched state.
18642    *
18643    * This method can be called to remove the 'ng-touched' class and set the form controls to their
18644    * untouched state (ng-untouched class).
18645    *
18646    * Setting a form controls back to their untouched state is often useful when setting the form
18647    * back to its pristine state.
18648    */
18649   form.$setUntouched = function() {
18650     forEach(controls, function(control) {
18651       control.$setUntouched();
18652     });
18653   };
18654
18655   /**
18656    * @ngdoc method
18657    * @name form.FormController#$setSubmitted
18658    *
18659    * @description
18660    * Sets the form to its submitted state.
18661    */
18662   form.$setSubmitted = function() {
18663     $animate.addClass(element, SUBMITTED_CLASS);
18664     form.$submitted = true;
18665     parentForm.$setSubmitted();
18666   };
18667 }
18668
18669 /**
18670  * @ngdoc directive
18671  * @name ngForm
18672  * @restrict EAC
18673  *
18674  * @description
18675  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
18676  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
18677  * sub-group of controls needs to be determined.
18678  *
18679  * Note: the purpose of `ngForm` is to group controls,
18680  * but not to be a replacement for the `<form>` tag with all of its capabilities
18681  * (e.g. posting to the server, ...).
18682  *
18683  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
18684  *                       related scope, under this name.
18685  *
18686  */
18687
18688  /**
18689  * @ngdoc directive
18690  * @name form
18691  * @restrict E
18692  *
18693  * @description
18694  * Directive that instantiates
18695  * {@link form.FormController FormController}.
18696  *
18697  * If the `name` attribute is specified, the form controller is published onto the current scope under
18698  * this name.
18699  *
18700  * # Alias: {@link ng.directive:ngForm `ngForm`}
18701  *
18702  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
18703  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
18704  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
18705  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
18706  * using Angular validation directives in forms that are dynamically generated using the
18707  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
18708  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
18709  * `ngForm` directive and nest these in an outer `form` element.
18710  *
18711  *
18712  * # CSS classes
18713  *  - `ng-valid` is set if the form is valid.
18714  *  - `ng-invalid` is set if the form is invalid.
18715  *  - `ng-pristine` is set if the form is pristine.
18716  *  - `ng-dirty` is set if the form is dirty.
18717  *  - `ng-submitted` is set if the form was submitted.
18718  *
18719  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
18720  *
18721  *
18722  * # Submitting a form and preventing the default action
18723  *
18724  * Since the role of forms in client-side Angular applications is different than in classical
18725  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
18726  * page reload that sends the data to the server. Instead some javascript logic should be triggered
18727  * to handle the form submission in an application-specific way.
18728  *
18729  * For this reason, Angular prevents the default action (form submission to the server) unless the
18730  * `<form>` element has an `action` attribute specified.
18731  *
18732  * You can use one of the following two ways to specify what javascript method should be called when
18733  * a form is submitted:
18734  *
18735  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
18736  * - {@link ng.directive:ngClick ngClick} directive on the first
18737   *  button or input field of type submit (input[type=submit])
18738  *
18739  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
18740  * or {@link ng.directive:ngClick ngClick} directives.
18741  * This is because of the following form submission rules in the HTML specification:
18742  *
18743  * - If a form has only one input field then hitting enter in this field triggers form submit
18744  * (`ngSubmit`)
18745  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
18746  * doesn't trigger submit
18747  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
18748  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
18749  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
18750  *
18751  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
18752  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
18753  * to have access to the updated model.
18754  *
18755  * ## Animation Hooks
18756  *
18757  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
18758  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
18759  * other validations that are performed within the form. Animations in ngForm are similar to how
18760  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
18761  * as JS animations.
18762  *
18763  * The following example shows a simple way to utilize CSS transitions to style a form element
18764  * that has been rendered as invalid after it has been validated:
18765  *
18766  * <pre>
18767  * //be sure to include ngAnimate as a module to hook into more
18768  * //advanced animations
18769  * .my-form {
18770  *   transition:0.5s linear all;
18771  *   background: white;
18772  * }
18773  * .my-form.ng-invalid {
18774  *   background: red;
18775  *   color:white;
18776  * }
18777  * </pre>
18778  *
18779  * @example
18780     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
18781       <file name="index.html">
18782        <script>
18783          angular.module('formExample', [])
18784            .controller('FormController', ['$scope', function($scope) {
18785              $scope.userType = 'guest';
18786            }]);
18787        </script>
18788        <style>
18789         .my-form {
18790           -webkit-transition:all linear 0.5s;
18791           transition:all linear 0.5s;
18792           background: transparent;
18793         }
18794         .my-form.ng-invalid {
18795           background: red;
18796         }
18797        </style>
18798        <form name="myForm" ng-controller="FormController" class="my-form">
18799          userType: <input name="input" ng-model="userType" required>
18800          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
18801          <code>userType = {{userType}}</code><br>
18802          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
18803          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
18804          <code>myForm.$valid = {{myForm.$valid}}</code><br>
18805          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
18806         </form>
18807       </file>
18808       <file name="protractor.js" type="protractor">
18809         it('should initialize to model', function() {
18810           var userType = element(by.binding('userType'));
18811           var valid = element(by.binding('myForm.input.$valid'));
18812
18813           expect(userType.getText()).toContain('guest');
18814           expect(valid.getText()).toContain('true');
18815         });
18816
18817         it('should be invalid if empty', function() {
18818           var userType = element(by.binding('userType'));
18819           var valid = element(by.binding('myForm.input.$valid'));
18820           var userInput = element(by.model('userType'));
18821
18822           userInput.clear();
18823           userInput.sendKeys('');
18824
18825           expect(userType.getText()).toEqual('userType =');
18826           expect(valid.getText()).toContain('false');
18827         });
18828       </file>
18829     </example>
18830  *
18831  * @param {string=} name Name of the form. If specified, the form controller will be published into
18832  *                       related scope, under this name.
18833  */
18834 var formDirectiveFactory = function(isNgForm) {
18835   return ['$timeout', function($timeout) {
18836     var formDirective = {
18837       name: 'form',
18838       restrict: isNgForm ? 'EAC' : 'E',
18839       controller: FormController,
18840       compile: function ngFormCompile(formElement, attr) {
18841         // Setup initial state of the control
18842         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
18843
18844         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
18845
18846         return {
18847           pre: function ngFormPreLink(scope, formElement, attr, controller) {
18848             // if `action` attr is not present on the form, prevent the default action (submission)
18849             if (!('action' in attr)) {
18850               // we can't use jq events because if a form is destroyed during submission the default
18851               // action is not prevented. see #1238
18852               //
18853               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
18854               // page reload if the form was destroyed by submission of the form via a click handler
18855               // on a button in the form. Looks like an IE9 specific bug.
18856               var handleFormSubmission = function(event) {
18857                 scope.$apply(function() {
18858                   controller.$commitViewValue();
18859                   controller.$setSubmitted();
18860                 });
18861
18862                 event.preventDefault();
18863               };
18864
18865               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18866
18867               // unregister the preventDefault listener so that we don't not leak memory but in a
18868               // way that will achieve the prevention of the default action.
18869               formElement.on('$destroy', function() {
18870                 $timeout(function() {
18871                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18872                 }, 0, false);
18873               });
18874             }
18875
18876             var parentFormCtrl = controller.$$parentForm;
18877
18878             if (nameAttr) {
18879               setter(scope, null, controller.$name, controller, controller.$name);
18880               attr.$observe(nameAttr, function(newValue) {
18881                 if (controller.$name === newValue) return;
18882                 setter(scope, null, controller.$name, undefined, controller.$name);
18883                 parentFormCtrl.$$renameControl(controller, newValue);
18884                 setter(scope, null, controller.$name, controller, controller.$name);
18885               });
18886             }
18887             formElement.on('$destroy', function() {
18888               parentFormCtrl.$removeControl(controller);
18889               if (nameAttr) {
18890                 setter(scope, null, attr[nameAttr], undefined, controller.$name);
18891               }
18892               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
18893             });
18894           }
18895         };
18896       }
18897     };
18898
18899     return formDirective;
18900   }];
18901 };
18902
18903 var formDirective = formDirectiveFactory();
18904 var ngFormDirective = formDirectiveFactory(true);
18905
18906 /* global VALID_CLASS: false,
18907   INVALID_CLASS: false,
18908   PRISTINE_CLASS: false,
18909   DIRTY_CLASS: false,
18910   UNTOUCHED_CLASS: false,
18911   TOUCHED_CLASS: false,
18912   ngModelMinErr: false,
18913 */
18914
18915 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
18916 var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
18917 var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
18918 var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
18919 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
18920 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
18921 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18922 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
18923 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
18924 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18925
18926 var inputType = {
18927
18928   /**
18929    * @ngdoc input
18930    * @name input[text]
18931    *
18932    * @description
18933    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
18934    *
18935    *
18936    * @param {string} ngModel Assignable angular expression to data-bind to.
18937    * @param {string=} name Property name of the form under which the control is published.
18938    * @param {string=} required Adds `required` validation error key if the value is not entered.
18939    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18940    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18941    *    `required` when you want to data-bind to the `required` attribute.
18942    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
18943    *    minlength.
18944    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
18945    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
18946    *    any length.
18947    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
18948    *    that contains the regular expression body that will be converted to a regular expression
18949    *    as in the ngPattern directive.
18950    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
18951    *    a RegExp found by evaluating the Angular expression given in the attribute value.
18952    *    If the expression evaluates to a RegExp object then this is used directly.
18953    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
18954    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
18955    * @param {string=} ngChange Angular expression to be executed when input changes due to user
18956    *    interaction with the input element.
18957    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
18958    *    This parameter is ignored for input[type=password] controls, which will never trim the
18959    *    input.
18960    *
18961    * @example
18962       <example name="text-input-directive" module="textInputExample">
18963         <file name="index.html">
18964          <script>
18965            angular.module('textInputExample', [])
18966              .controller('ExampleController', ['$scope', function($scope) {
18967                $scope.example = {
18968                  text: 'guest',
18969                  word: /^\s*\w*\s*$/
18970                };
18971              }]);
18972          </script>
18973          <form name="myForm" ng-controller="ExampleController">
18974            Single word: <input type="text" name="input" ng-model="example.text"
18975                                ng-pattern="example.word" required ng-trim="false">
18976            <span class="error" ng-show="myForm.input.$error.required">
18977              Required!</span>
18978            <span class="error" ng-show="myForm.input.$error.pattern">
18979              Single word only!</span>
18980
18981            <tt>text = {{example.text}}</tt><br/>
18982            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18983            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18984            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18985            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18986           </form>
18987         </file>
18988         <file name="protractor.js" type="protractor">
18989           var text = element(by.binding('example.text'));
18990           var valid = element(by.binding('myForm.input.$valid'));
18991           var input = element(by.model('example.text'));
18992
18993           it('should initialize to model', function() {
18994             expect(text.getText()).toContain('guest');
18995             expect(valid.getText()).toContain('true');
18996           });
18997
18998           it('should be invalid if empty', function() {
18999             input.clear();
19000             input.sendKeys('');
19001
19002             expect(text.getText()).toEqual('text =');
19003             expect(valid.getText()).toContain('false');
19004           });
19005
19006           it('should be invalid if multi word', function() {
19007             input.clear();
19008             input.sendKeys('hello world');
19009
19010             expect(valid.getText()).toContain('false');
19011           });
19012         </file>
19013       </example>
19014    */
19015   'text': textInputType,
19016
19017     /**
19018      * @ngdoc input
19019      * @name input[date]
19020      *
19021      * @description
19022      * Input with date validation and transformation. In browsers that do not yet support
19023      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
19024      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
19025      * modern browsers do not yet support this input type, it is important to provide cues to users on the
19026      * expected input format via a placeholder or label.
19027      *
19028      * The model must always be a Date object, otherwise Angular will throw an error.
19029      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19030      *
19031      * The timezone to be used to read/write the `Date` instance in the model can be defined using
19032      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19033      *
19034      * @param {string} ngModel Assignable angular expression to data-bind to.
19035      * @param {string=} name Property name of the form under which the control is published.
19036      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19037      * valid ISO date string (yyyy-MM-dd).
19038      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
19039      * a valid ISO date string (yyyy-MM-dd).
19040      * @param {string=} required Sets `required` validation error key if the value is not entered.
19041      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19042      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19043      *    `required` when you want to data-bind to the `required` attribute.
19044      * @param {string=} ngChange Angular expression to be executed when input changes due to user
19045      *    interaction with the input element.
19046      *
19047      * @example
19048      <example name="date-input-directive" module="dateInputExample">
19049      <file name="index.html">
19050        <script>
19051           angular.module('dateInputExample', [])
19052             .controller('DateController', ['$scope', function($scope) {
19053               $scope.example = {
19054                 value: new Date(2013, 9, 22)
19055               };
19056             }]);
19057        </script>
19058        <form name="myForm" ng-controller="DateController as dateCtrl">
19059           Pick a date in 2013:
19060           <input type="date" id="exampleInput" name="input" ng-model="example.value"
19061               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
19062           <span class="error" ng-show="myForm.input.$error.required">
19063               Required!</span>
19064           <span class="error" ng-show="myForm.input.$error.date">
19065               Not a valid date!</span>
19066            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
19067            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19068            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19069            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19070            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19071        </form>
19072      </file>
19073      <file name="protractor.js" type="protractor">
19074         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
19075         var valid = element(by.binding('myForm.input.$valid'));
19076         var input = element(by.model('example.value'));
19077
19078         // currently protractor/webdriver does not support
19079         // sending keys to all known HTML5 input controls
19080         // for various browsers (see https://github.com/angular/protractor/issues/562).
19081         function setInput(val) {
19082           // set the value of the element and force validation.
19083           var scr = "var ipt = document.getElementById('exampleInput'); " +
19084           "ipt.value = '" + val + "';" +
19085           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19086           browser.executeScript(scr);
19087         }
19088
19089         it('should initialize to model', function() {
19090           expect(value.getText()).toContain('2013-10-22');
19091           expect(valid.getText()).toContain('myForm.input.$valid = true');
19092         });
19093
19094         it('should be invalid if empty', function() {
19095           setInput('');
19096           expect(value.getText()).toEqual('value =');
19097           expect(valid.getText()).toContain('myForm.input.$valid = false');
19098         });
19099
19100         it('should be invalid if over max', function() {
19101           setInput('2015-01-01');
19102           expect(value.getText()).toContain('');
19103           expect(valid.getText()).toContain('myForm.input.$valid = false');
19104         });
19105      </file>
19106      </example>
19107      */
19108   'date': createDateInputType('date', DATE_REGEXP,
19109          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
19110          'yyyy-MM-dd'),
19111
19112    /**
19113     * @ngdoc input
19114     * @name input[datetime-local]
19115     *
19116     * @description
19117     * Input with datetime validation and transformation. In browsers that do not yet support
19118     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19119     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
19120     *
19121     * The model must always be a Date object, otherwise Angular will throw an error.
19122     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19123     *
19124     * The timezone to be used to read/write the `Date` instance in the model can be defined using
19125     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19126     *
19127     * @param {string} ngModel Assignable angular expression to data-bind to.
19128     * @param {string=} name Property name of the form under which the control is published.
19129     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19130     * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
19131     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
19132     * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
19133     * @param {string=} required Sets `required` validation error key if the value is not entered.
19134     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19135     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19136     *    `required` when you want to data-bind to the `required` attribute.
19137     * @param {string=} ngChange Angular expression to be executed when input changes due to user
19138     *    interaction with the input element.
19139     *
19140     * @example
19141     <example name="datetimelocal-input-directive" module="dateExample">
19142     <file name="index.html">
19143       <script>
19144         angular.module('dateExample', [])
19145           .controller('DateController', ['$scope', function($scope) {
19146             $scope.example = {
19147               value: new Date(2010, 11, 28, 14, 57)
19148             };
19149           }]);
19150       </script>
19151       <form name="myForm" ng-controller="DateController as dateCtrl">
19152         Pick a date between in 2013:
19153         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
19154             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
19155         <span class="error" ng-show="myForm.input.$error.required">
19156             Required!</span>
19157         <span class="error" ng-show="myForm.input.$error.datetimelocal">
19158             Not a valid date!</span>
19159         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
19160         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19161         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19162         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19163         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19164       </form>
19165     </file>
19166     <file name="protractor.js" type="protractor">
19167       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
19168       var valid = element(by.binding('myForm.input.$valid'));
19169       var input = element(by.model('example.value'));
19170
19171       // currently protractor/webdriver does not support
19172       // sending keys to all known HTML5 input controls
19173       // for various browsers (https://github.com/angular/protractor/issues/562).
19174       function setInput(val) {
19175         // set the value of the element and force validation.
19176         var scr = "var ipt = document.getElementById('exampleInput'); " +
19177         "ipt.value = '" + val + "';" +
19178         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19179         browser.executeScript(scr);
19180       }
19181
19182       it('should initialize to model', function() {
19183         expect(value.getText()).toContain('2010-12-28T14:57:00');
19184         expect(valid.getText()).toContain('myForm.input.$valid = true');
19185       });
19186
19187       it('should be invalid if empty', function() {
19188         setInput('');
19189         expect(value.getText()).toEqual('value =');
19190         expect(valid.getText()).toContain('myForm.input.$valid = false');
19191       });
19192
19193       it('should be invalid if over max', function() {
19194         setInput('2015-01-01T23:59:00');
19195         expect(value.getText()).toContain('');
19196         expect(valid.getText()).toContain('myForm.input.$valid = false');
19197       });
19198     </file>
19199     </example>
19200     */
19201   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
19202       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
19203       'yyyy-MM-ddTHH:mm:ss.sss'),
19204
19205   /**
19206    * @ngdoc input
19207    * @name input[time]
19208    *
19209    * @description
19210    * Input with time validation and transformation. In browsers that do not yet support
19211    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19212    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
19213    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
19214    *
19215    * The model must always be a Date object, otherwise Angular will throw an error.
19216    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19217    *
19218    * The timezone to be used to read/write the `Date` instance in the model can be defined using
19219    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19220    *
19221    * @param {string} ngModel Assignable angular expression to data-bind to.
19222    * @param {string=} name Property name of the form under which the control is published.
19223    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19224    * valid ISO time format (HH:mm:ss).
19225    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
19226    * valid ISO time format (HH:mm:ss).
19227    * @param {string=} required Sets `required` validation error key if the value is not entered.
19228    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19229    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19230    *    `required` when you want to data-bind to the `required` attribute.
19231    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19232    *    interaction with the input element.
19233    *
19234    * @example
19235    <example name="time-input-directive" module="timeExample">
19236    <file name="index.html">
19237      <script>
19238       angular.module('timeExample', [])
19239         .controller('DateController', ['$scope', function($scope) {
19240           $scope.example = {
19241             value: new Date(1970, 0, 1, 14, 57, 0)
19242           };
19243         }]);
19244      </script>
19245      <form name="myForm" ng-controller="DateController as dateCtrl">
19246         Pick a between 8am and 5pm:
19247         <input type="time" id="exampleInput" name="input" ng-model="example.value"
19248             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
19249         <span class="error" ng-show="myForm.input.$error.required">
19250             Required!</span>
19251         <span class="error" ng-show="myForm.input.$error.time">
19252             Not a valid date!</span>
19253         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
19254         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19255         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19256         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19257         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19258      </form>
19259    </file>
19260    <file name="protractor.js" type="protractor">
19261       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
19262       var valid = element(by.binding('myForm.input.$valid'));
19263       var input = element(by.model('example.value'));
19264
19265       // currently protractor/webdriver does not support
19266       // sending keys to all known HTML5 input controls
19267       // for various browsers (https://github.com/angular/protractor/issues/562).
19268       function setInput(val) {
19269         // set the value of the element and force validation.
19270         var scr = "var ipt = document.getElementById('exampleInput'); " +
19271         "ipt.value = '" + val + "';" +
19272         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19273         browser.executeScript(scr);
19274       }
19275
19276       it('should initialize to model', function() {
19277         expect(value.getText()).toContain('14:57:00');
19278         expect(valid.getText()).toContain('myForm.input.$valid = true');
19279       });
19280
19281       it('should be invalid if empty', function() {
19282         setInput('');
19283         expect(value.getText()).toEqual('value =');
19284         expect(valid.getText()).toContain('myForm.input.$valid = false');
19285       });
19286
19287       it('should be invalid if over max', function() {
19288         setInput('23:59:00');
19289         expect(value.getText()).toContain('');
19290         expect(valid.getText()).toContain('myForm.input.$valid = false');
19291       });
19292    </file>
19293    </example>
19294    */
19295   'time': createDateInputType('time', TIME_REGEXP,
19296       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
19297      'HH:mm:ss.sss'),
19298
19299    /**
19300     * @ngdoc input
19301     * @name input[week]
19302     *
19303     * @description
19304     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
19305     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19306     * week format (yyyy-W##), for example: `2013-W02`.
19307     *
19308     * The model must always be a Date object, otherwise Angular will throw an error.
19309     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19310     *
19311     * The timezone to be used to read/write the `Date` instance in the model can be defined using
19312     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19313     *
19314     * @param {string} ngModel Assignable angular expression to data-bind to.
19315     * @param {string=} name Property name of the form under which the control is published.
19316     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19317     * valid ISO week format (yyyy-W##).
19318     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
19319     * a valid ISO week format (yyyy-W##).
19320     * @param {string=} required Sets `required` validation error key if the value is not entered.
19321     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19322     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19323     *    `required` when you want to data-bind to the `required` attribute.
19324     * @param {string=} ngChange Angular expression to be executed when input changes due to user
19325     *    interaction with the input element.
19326     *
19327     * @example
19328     <example name="week-input-directive" module="weekExample">
19329     <file name="index.html">
19330       <script>
19331       angular.module('weekExample', [])
19332         .controller('DateController', ['$scope', function($scope) {
19333           $scope.example = {
19334             value: new Date(2013, 0, 3)
19335           };
19336         }]);
19337       </script>
19338       <form name="myForm" ng-controller="DateController as dateCtrl">
19339         Pick a date between in 2013:
19340         <input id="exampleInput" type="week" name="input" ng-model="example.value"
19341             placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
19342         <span class="error" ng-show="myForm.input.$error.required">
19343             Required!</span>
19344         <span class="error" ng-show="myForm.input.$error.week">
19345             Not a valid date!</span>
19346         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
19347         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19348         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19349         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19350         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19351       </form>
19352     </file>
19353     <file name="protractor.js" type="protractor">
19354       var value = element(by.binding('example.value | date: "yyyy-Www"'));
19355       var valid = element(by.binding('myForm.input.$valid'));
19356       var input = element(by.model('example.value'));
19357
19358       // currently protractor/webdriver does not support
19359       // sending keys to all known HTML5 input controls
19360       // for various browsers (https://github.com/angular/protractor/issues/562).
19361       function setInput(val) {
19362         // set the value of the element and force validation.
19363         var scr = "var ipt = document.getElementById('exampleInput'); " +
19364         "ipt.value = '" + val + "';" +
19365         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19366         browser.executeScript(scr);
19367       }
19368
19369       it('should initialize to model', function() {
19370         expect(value.getText()).toContain('2013-W01');
19371         expect(valid.getText()).toContain('myForm.input.$valid = true');
19372       });
19373
19374       it('should be invalid if empty', function() {
19375         setInput('');
19376         expect(value.getText()).toEqual('value =');
19377         expect(valid.getText()).toContain('myForm.input.$valid = false');
19378       });
19379
19380       it('should be invalid if over max', function() {
19381         setInput('2015-W01');
19382         expect(value.getText()).toContain('');
19383         expect(valid.getText()).toContain('myForm.input.$valid = false');
19384       });
19385     </file>
19386     </example>
19387     */
19388   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
19389
19390   /**
19391    * @ngdoc input
19392    * @name input[month]
19393    *
19394    * @description
19395    * Input with month validation and transformation. In browsers that do not yet support
19396    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19397    * month format (yyyy-MM), for example: `2009-01`.
19398    *
19399    * The model must always be a Date object, otherwise Angular will throw an error.
19400    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19401    * If the model is not set to the first of the month, the next view to model update will set it
19402    * to the first of the month.
19403    *
19404    * The timezone to be used to read/write the `Date` instance in the model can be defined using
19405    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19406    *
19407    * @param {string} ngModel Assignable angular expression to data-bind to.
19408    * @param {string=} name Property name of the form under which the control is published.
19409    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
19410    * a valid ISO month format (yyyy-MM).
19411    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
19412    * be a valid ISO month format (yyyy-MM).
19413    * @param {string=} required Sets `required` validation error key if the value is not entered.
19414    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19415    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19416    *    `required` when you want to data-bind to the `required` attribute.
19417    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19418    *    interaction with the input element.
19419    *
19420    * @example
19421    <example name="month-input-directive" module="monthExample">
19422    <file name="index.html">
19423      <script>
19424       angular.module('monthExample', [])
19425         .controller('DateController', ['$scope', function($scope) {
19426           $scope.example = {
19427             value: new Date(2013, 9, 1)
19428           };
19429         }]);
19430      </script>
19431      <form name="myForm" ng-controller="DateController as dateCtrl">
19432        Pick a month in 2013:
19433        <input id="exampleInput" type="month" name="input" ng-model="example.value"
19434           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
19435        <span class="error" ng-show="myForm.input.$error.required">
19436           Required!</span>
19437        <span class="error" ng-show="myForm.input.$error.month">
19438           Not a valid month!</span>
19439        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
19440        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19441        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19442        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19443        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19444      </form>
19445    </file>
19446    <file name="protractor.js" type="protractor">
19447       var value = element(by.binding('example.value | date: "yyyy-MM"'));
19448       var valid = element(by.binding('myForm.input.$valid'));
19449       var input = element(by.model('example.value'));
19450
19451       // currently protractor/webdriver does not support
19452       // sending keys to all known HTML5 input controls
19453       // for various browsers (https://github.com/angular/protractor/issues/562).
19454       function setInput(val) {
19455         // set the value of the element and force validation.
19456         var scr = "var ipt = document.getElementById('exampleInput'); " +
19457         "ipt.value = '" + val + "';" +
19458         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19459         browser.executeScript(scr);
19460       }
19461
19462       it('should initialize to model', function() {
19463         expect(value.getText()).toContain('2013-10');
19464         expect(valid.getText()).toContain('myForm.input.$valid = true');
19465       });
19466
19467       it('should be invalid if empty', function() {
19468         setInput('');
19469         expect(value.getText()).toEqual('value =');
19470         expect(valid.getText()).toContain('myForm.input.$valid = false');
19471       });
19472
19473       it('should be invalid if over max', function() {
19474         setInput('2015-01');
19475         expect(value.getText()).toContain('');
19476         expect(valid.getText()).toContain('myForm.input.$valid = false');
19477       });
19478    </file>
19479    </example>
19480    */
19481   'month': createDateInputType('month', MONTH_REGEXP,
19482      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
19483      'yyyy-MM'),
19484
19485   /**
19486    * @ngdoc input
19487    * @name input[number]
19488    *
19489    * @description
19490    * Text input with number validation and transformation. Sets the `number` validation
19491    * error if not a valid number.
19492    *
19493    * <div class="alert alert-warning">
19494    * The model must always be of type `number` otherwise Angular will throw an error.
19495    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
19496    * error docs for more information and an example of how to convert your model if necessary.
19497    * </div>
19498    *
19499    * @param {string} ngModel Assignable angular expression to data-bind to.
19500    * @param {string=} name Property name of the form under which the control is published.
19501    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
19502    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
19503    * @param {string=} required Sets `required` validation error key if the value is not entered.
19504    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19505    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19506    *    `required` when you want to data-bind to the `required` attribute.
19507    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19508    *    minlength.
19509    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19510    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19511    *    any length.
19512    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19513    *    that contains the regular expression body that will be converted to a regular expression
19514    *    as in the ngPattern directive.
19515    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19516    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19517    *    If the expression evaluates to a RegExp object then this is used directly.
19518    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19519    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19520    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19521    *    interaction with the input element.
19522    *
19523    * @example
19524       <example name="number-input-directive" module="numberExample">
19525         <file name="index.html">
19526          <script>
19527            angular.module('numberExample', [])
19528              .controller('ExampleController', ['$scope', function($scope) {
19529                $scope.example = {
19530                  value: 12
19531                };
19532              }]);
19533          </script>
19534          <form name="myForm" ng-controller="ExampleController">
19535            Number: <input type="number" name="input" ng-model="example.value"
19536                           min="0" max="99" required>
19537            <span class="error" ng-show="myForm.input.$error.required">
19538              Required!</span>
19539            <span class="error" ng-show="myForm.input.$error.number">
19540              Not valid number!</span>
19541            <tt>value = {{example.value}}</tt><br/>
19542            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19543            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19544            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19545            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19546           </form>
19547         </file>
19548         <file name="protractor.js" type="protractor">
19549           var value = element(by.binding('example.value'));
19550           var valid = element(by.binding('myForm.input.$valid'));
19551           var input = element(by.model('example.value'));
19552
19553           it('should initialize to model', function() {
19554             expect(value.getText()).toContain('12');
19555             expect(valid.getText()).toContain('true');
19556           });
19557
19558           it('should be invalid if empty', function() {
19559             input.clear();
19560             input.sendKeys('');
19561             expect(value.getText()).toEqual('value =');
19562             expect(valid.getText()).toContain('false');
19563           });
19564
19565           it('should be invalid if over max', function() {
19566             input.clear();
19567             input.sendKeys('123');
19568             expect(value.getText()).toEqual('value =');
19569             expect(valid.getText()).toContain('false');
19570           });
19571         </file>
19572       </example>
19573    */
19574   'number': numberInputType,
19575
19576
19577   /**
19578    * @ngdoc input
19579    * @name input[url]
19580    *
19581    * @description
19582    * Text input with URL validation. Sets the `url` validation error key if the content is not a
19583    * valid URL.
19584    *
19585    * <div class="alert alert-warning">
19586    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
19587    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
19588    * the built-in validators (see the {@link guide/forms Forms guide})
19589    * </div>
19590    *
19591    * @param {string} ngModel Assignable angular expression to data-bind to.
19592    * @param {string=} name Property name of the form under which the control is published.
19593    * @param {string=} required Sets `required` validation error key if the value is not entered.
19594    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19595    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19596    *    `required` when you want to data-bind to the `required` attribute.
19597    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19598    *    minlength.
19599    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19600    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19601    *    any length.
19602    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19603    *    that contains the regular expression body that will be converted to a regular expression
19604    *    as in the ngPattern directive.
19605    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19606    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19607    *    If the expression evaluates to a RegExp object then this is used directly.
19608    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19609    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19610    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19611    *    interaction with the input element.
19612    *
19613    * @example
19614       <example name="url-input-directive" module="urlExample">
19615         <file name="index.html">
19616          <script>
19617            angular.module('urlExample', [])
19618              .controller('ExampleController', ['$scope', function($scope) {
19619                $scope.url = {
19620                  text: 'http://google.com'
19621                };
19622              }]);
19623          </script>
19624          <form name="myForm" ng-controller="ExampleController">
19625            URL: <input type="url" name="input" ng-model="url.text" required>
19626            <span class="error" ng-show="myForm.input.$error.required">
19627              Required!</span>
19628            <span class="error" ng-show="myForm.input.$error.url">
19629              Not valid url!</span>
19630            <tt>text = {{url.text}}</tt><br/>
19631            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19632            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19633            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19634            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19635            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
19636           </form>
19637         </file>
19638         <file name="protractor.js" type="protractor">
19639           var text = element(by.binding('url.text'));
19640           var valid = element(by.binding('myForm.input.$valid'));
19641           var input = element(by.model('url.text'));
19642
19643           it('should initialize to model', function() {
19644             expect(text.getText()).toContain('http://google.com');
19645             expect(valid.getText()).toContain('true');
19646           });
19647
19648           it('should be invalid if empty', function() {
19649             input.clear();
19650             input.sendKeys('');
19651
19652             expect(text.getText()).toEqual('text =');
19653             expect(valid.getText()).toContain('false');
19654           });
19655
19656           it('should be invalid if not url', function() {
19657             input.clear();
19658             input.sendKeys('box');
19659
19660             expect(valid.getText()).toContain('false');
19661           });
19662         </file>
19663       </example>
19664    */
19665   'url': urlInputType,
19666
19667
19668   /**
19669    * @ngdoc input
19670    * @name input[email]
19671    *
19672    * @description
19673    * Text input with email validation. Sets the `email` validation error key if not a valid email
19674    * address.
19675    *
19676    * <div class="alert alert-warning">
19677    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
19678    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
19679    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
19680    * </div>
19681    *
19682    * @param {string} ngModel Assignable angular expression to data-bind to.
19683    * @param {string=} name Property name of the form under which the control is published.
19684    * @param {string=} required Sets `required` validation error key if the value is not entered.
19685    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19686    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19687    *    `required` when you want to data-bind to the `required` attribute.
19688    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19689    *    minlength.
19690    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19691    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19692    *    any length.
19693    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19694    *    that contains the regular expression body that will be converted to a regular expression
19695    *    as in the ngPattern directive.
19696    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19697    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19698    *    If the expression evaluates to a RegExp object then this is used directly.
19699    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19700    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19701    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19702    *    interaction with the input element.
19703    *
19704    * @example
19705       <example name="email-input-directive" module="emailExample">
19706         <file name="index.html">
19707          <script>
19708            angular.module('emailExample', [])
19709              .controller('ExampleController', ['$scope', function($scope) {
19710                $scope.email = {
19711                  text: 'me@example.com'
19712                };
19713              }]);
19714          </script>
19715            <form name="myForm" ng-controller="ExampleController">
19716              Email: <input type="email" name="input" ng-model="email.text" required>
19717              <span class="error" ng-show="myForm.input.$error.required">
19718                Required!</span>
19719              <span class="error" ng-show="myForm.input.$error.email">
19720                Not valid email!</span>
19721              <tt>text = {{email.text}}</tt><br/>
19722              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19723              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19724              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19725              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19726              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
19727            </form>
19728          </file>
19729         <file name="protractor.js" type="protractor">
19730           var text = element(by.binding('email.text'));
19731           var valid = element(by.binding('myForm.input.$valid'));
19732           var input = element(by.model('email.text'));
19733
19734           it('should initialize to model', function() {
19735             expect(text.getText()).toContain('me@example.com');
19736             expect(valid.getText()).toContain('true');
19737           });
19738
19739           it('should be invalid if empty', function() {
19740             input.clear();
19741             input.sendKeys('');
19742             expect(text.getText()).toEqual('text =');
19743             expect(valid.getText()).toContain('false');
19744           });
19745
19746           it('should be invalid if not email', function() {
19747             input.clear();
19748             input.sendKeys('xxx');
19749
19750             expect(valid.getText()).toContain('false');
19751           });
19752         </file>
19753       </example>
19754    */
19755   'email': emailInputType,
19756
19757
19758   /**
19759    * @ngdoc input
19760    * @name input[radio]
19761    *
19762    * @description
19763    * HTML radio button.
19764    *
19765    * @param {string} ngModel Assignable angular expression to data-bind to.
19766    * @param {string} value The value to which the expression should be set when selected.
19767    * @param {string=} name Property name of the form under which the control is published.
19768    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19769    *    interaction with the input element.
19770    * @param {string} ngValue Angular expression which sets the value to which the expression should
19771    *    be set when selected.
19772    *
19773    * @example
19774       <example name="radio-input-directive" module="radioExample">
19775         <file name="index.html">
19776          <script>
19777            angular.module('radioExample', [])
19778              .controller('ExampleController', ['$scope', function($scope) {
19779                $scope.color = {
19780                  name: 'blue'
19781                };
19782                $scope.specialValue = {
19783                  "id": "12345",
19784                  "value": "green"
19785                };
19786              }]);
19787          </script>
19788          <form name="myForm" ng-controller="ExampleController">
19789            <input type="radio" ng-model="color.name" value="red">  Red <br/>
19790            <input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
19791            <input type="radio" ng-model="color.name" value="blue"> Blue <br/>
19792            <tt>color = {{color.name | json}}</tt><br/>
19793           </form>
19794           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
19795         </file>
19796         <file name="protractor.js" type="protractor">
19797           it('should change state', function() {
19798             var color = element(by.binding('color.name'));
19799
19800             expect(color.getText()).toContain('blue');
19801
19802             element.all(by.model('color.name')).get(0).click();
19803
19804             expect(color.getText()).toContain('red');
19805           });
19806         </file>
19807       </example>
19808    */
19809   'radio': radioInputType,
19810
19811
19812   /**
19813    * @ngdoc input
19814    * @name input[checkbox]
19815    *
19816    * @description
19817    * HTML checkbox.
19818    *
19819    * @param {string} ngModel Assignable angular expression to data-bind to.
19820    * @param {string=} name Property name of the form under which the control is published.
19821    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
19822    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
19823    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19824    *    interaction with the input element.
19825    *
19826    * @example
19827       <example name="checkbox-input-directive" module="checkboxExample">
19828         <file name="index.html">
19829          <script>
19830            angular.module('checkboxExample', [])
19831              .controller('ExampleController', ['$scope', function($scope) {
19832                $scope.checkboxModel = {
19833                 value1 : true,
19834                 value2 : 'YES'
19835               };
19836              }]);
19837          </script>
19838          <form name="myForm" ng-controller="ExampleController">
19839            Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
19840            Value2: <input type="checkbox" ng-model="checkboxModel.value2"
19841                           ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
19842            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
19843            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
19844           </form>
19845         </file>
19846         <file name="protractor.js" type="protractor">
19847           it('should change state', function() {
19848             var value1 = element(by.binding('checkboxModel.value1'));
19849             var value2 = element(by.binding('checkboxModel.value2'));
19850
19851             expect(value1.getText()).toContain('true');
19852             expect(value2.getText()).toContain('YES');
19853
19854             element(by.model('checkboxModel.value1')).click();
19855             element(by.model('checkboxModel.value2')).click();
19856
19857             expect(value1.getText()).toContain('false');
19858             expect(value2.getText()).toContain('NO');
19859           });
19860         </file>
19861       </example>
19862    */
19863   'checkbox': checkboxInputType,
19864
19865   'hidden': noop,
19866   'button': noop,
19867   'submit': noop,
19868   'reset': noop,
19869   'file': noop
19870 };
19871
19872 function stringBasedInputType(ctrl) {
19873   ctrl.$formatters.push(function(value) {
19874     return ctrl.$isEmpty(value) ? value : value.toString();
19875   });
19876 }
19877
19878 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19879   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19880   stringBasedInputType(ctrl);
19881 }
19882
19883 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19884   var type = lowercase(element[0].type);
19885
19886   // In composition mode, users are still inputing intermediate text buffer,
19887   // hold the listener until composition is done.
19888   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
19889   if (!$sniffer.android) {
19890     var composing = false;
19891
19892     element.on('compositionstart', function(data) {
19893       composing = true;
19894     });
19895
19896     element.on('compositionend', function() {
19897       composing = false;
19898       listener();
19899     });
19900   }
19901
19902   var listener = function(ev) {
19903     if (timeout) {
19904       $browser.defer.cancel(timeout);
19905       timeout = null;
19906     }
19907     if (composing) return;
19908     var value = element.val(),
19909         event = ev && ev.type;
19910
19911     // By default we will trim the value
19912     // If the attribute ng-trim exists we will avoid trimming
19913     // If input type is 'password', the value is never trimmed
19914     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
19915       value = trim(value);
19916     }
19917
19918     // If a control is suffering from bad input (due to native validators), browsers discard its
19919     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
19920     // control's value is the same empty value twice in a row.
19921     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
19922       ctrl.$setViewValue(value, event);
19923     }
19924   };
19925
19926   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
19927   // input event on backspace, delete or cut
19928   if ($sniffer.hasEvent('input')) {
19929     element.on('input', listener);
19930   } else {
19931     var timeout;
19932
19933     var deferListener = function(ev, input, origValue) {
19934       if (!timeout) {
19935         timeout = $browser.defer(function() {
19936           timeout = null;
19937           if (!input || input.value !== origValue) {
19938             listener(ev);
19939           }
19940         });
19941       }
19942     };
19943
19944     element.on('keydown', function(event) {
19945       var key = event.keyCode;
19946
19947       // ignore
19948       //    command            modifiers                   arrows
19949       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
19950
19951       deferListener(event, this, this.value);
19952     });
19953
19954     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
19955     if ($sniffer.hasEvent('paste')) {
19956       element.on('paste cut', deferListener);
19957     }
19958   }
19959
19960   // if user paste into input using mouse on older browser
19961   // or form autocomplete on newer browser, we need "change" event to catch it
19962   element.on('change', listener);
19963
19964   ctrl.$render = function() {
19965     element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
19966   };
19967 }
19968
19969 function weekParser(isoWeek, existingDate) {
19970   if (isDate(isoWeek)) {
19971     return isoWeek;
19972   }
19973
19974   if (isString(isoWeek)) {
19975     WEEK_REGEXP.lastIndex = 0;
19976     var parts = WEEK_REGEXP.exec(isoWeek);
19977     if (parts) {
19978       var year = +parts[1],
19979           week = +parts[2],
19980           hours = 0,
19981           minutes = 0,
19982           seconds = 0,
19983           milliseconds = 0,
19984           firstThurs = getFirstThursdayOfYear(year),
19985           addDays = (week - 1) * 7;
19986
19987       if (existingDate) {
19988         hours = existingDate.getHours();
19989         minutes = existingDate.getMinutes();
19990         seconds = existingDate.getSeconds();
19991         milliseconds = existingDate.getMilliseconds();
19992       }
19993
19994       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
19995     }
19996   }
19997
19998   return NaN;
19999 }
20000
20001 function createDateParser(regexp, mapping) {
20002   return function(iso, date) {
20003     var parts, map;
20004
20005     if (isDate(iso)) {
20006       return iso;
20007     }
20008
20009     if (isString(iso)) {
20010       // When a date is JSON'ified to wraps itself inside of an extra
20011       // set of double quotes. This makes the date parsing code unable
20012       // to match the date string and parse it as a date.
20013       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
20014         iso = iso.substring(1, iso.length - 1);
20015       }
20016       if (ISO_DATE_REGEXP.test(iso)) {
20017         return new Date(iso);
20018       }
20019       regexp.lastIndex = 0;
20020       parts = regexp.exec(iso);
20021
20022       if (parts) {
20023         parts.shift();
20024         if (date) {
20025           map = {
20026             yyyy: date.getFullYear(),
20027             MM: date.getMonth() + 1,
20028             dd: date.getDate(),
20029             HH: date.getHours(),
20030             mm: date.getMinutes(),
20031             ss: date.getSeconds(),
20032             sss: date.getMilliseconds() / 1000
20033           };
20034         } else {
20035           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
20036         }
20037
20038         forEach(parts, function(part, index) {
20039           if (index < mapping.length) {
20040             map[mapping[index]] = +part;
20041           }
20042         });
20043         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
20044       }
20045     }
20046
20047     return NaN;
20048   };
20049 }
20050
20051 function createDateInputType(type, regexp, parseDate, format) {
20052   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
20053     badInputChecker(scope, element, attr, ctrl);
20054     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20055     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
20056     var previousDate;
20057
20058     ctrl.$$parserName = type;
20059     ctrl.$parsers.push(function(value) {
20060       if (ctrl.$isEmpty(value)) return null;
20061       if (regexp.test(value)) {
20062         // Note: We cannot read ctrl.$modelValue, as there might be a different
20063         // parser/formatter in the processing chain so that the model
20064         // contains some different data format!
20065         var parsedDate = parseDate(value, previousDate);
20066         if (timezone === 'UTC') {
20067           parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
20068         }
20069         return parsedDate;
20070       }
20071       return undefined;
20072     });
20073
20074     ctrl.$formatters.push(function(value) {
20075       if (value && !isDate(value)) {
20076         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
20077       }
20078       if (isValidDate(value)) {
20079         previousDate = value;
20080         if (previousDate && timezone === 'UTC') {
20081           var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
20082           previousDate = new Date(previousDate.getTime() + timezoneOffset);
20083         }
20084         return $filter('date')(value, format, timezone);
20085       } else {
20086         previousDate = null;
20087         return '';
20088       }
20089     });
20090
20091     if (isDefined(attr.min) || attr.ngMin) {
20092       var minVal;
20093       ctrl.$validators.min = function(value) {
20094         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
20095       };
20096       attr.$observe('min', function(val) {
20097         minVal = parseObservedDateValue(val);
20098         ctrl.$validate();
20099       });
20100     }
20101
20102     if (isDefined(attr.max) || attr.ngMax) {
20103       var maxVal;
20104       ctrl.$validators.max = function(value) {
20105         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
20106       };
20107       attr.$observe('max', function(val) {
20108         maxVal = parseObservedDateValue(val);
20109         ctrl.$validate();
20110       });
20111     }
20112
20113     function isValidDate(value) {
20114       // Invalid Date: getTime() returns NaN
20115       return value && !(value.getTime && value.getTime() !== value.getTime());
20116     }
20117
20118     function parseObservedDateValue(val) {
20119       return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
20120     }
20121   };
20122 }
20123
20124 function badInputChecker(scope, element, attr, ctrl) {
20125   var node = element[0];
20126   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
20127   if (nativeValidation) {
20128     ctrl.$parsers.push(function(value) {
20129       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
20130       // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
20131       // - also sets validity.badInput (should only be validity.typeMismatch).
20132       // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
20133       // - can ignore this case as we can still read out the erroneous email...
20134       return validity.badInput && !validity.typeMismatch ? undefined : value;
20135     });
20136   }
20137 }
20138
20139 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20140   badInputChecker(scope, element, attr, ctrl);
20141   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20142
20143   ctrl.$$parserName = 'number';
20144   ctrl.$parsers.push(function(value) {
20145     if (ctrl.$isEmpty(value))      return null;
20146     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
20147     return undefined;
20148   });
20149
20150   ctrl.$formatters.push(function(value) {
20151     if (!ctrl.$isEmpty(value)) {
20152       if (!isNumber(value)) {
20153         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
20154       }
20155       value = value.toString();
20156     }
20157     return value;
20158   });
20159
20160   if (isDefined(attr.min) || attr.ngMin) {
20161     var minVal;
20162     ctrl.$validators.min = function(value) {
20163       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
20164     };
20165
20166     attr.$observe('min', function(val) {
20167       if (isDefined(val) && !isNumber(val)) {
20168         val = parseFloat(val, 10);
20169       }
20170       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
20171       // TODO(matsko): implement validateLater to reduce number of validations
20172       ctrl.$validate();
20173     });
20174   }
20175
20176   if (isDefined(attr.max) || attr.ngMax) {
20177     var maxVal;
20178     ctrl.$validators.max = function(value) {
20179       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
20180     };
20181
20182     attr.$observe('max', function(val) {
20183       if (isDefined(val) && !isNumber(val)) {
20184         val = parseFloat(val, 10);
20185       }
20186       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
20187       // TODO(matsko): implement validateLater to reduce number of validations
20188       ctrl.$validate();
20189     });
20190   }
20191 }
20192
20193 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20194   // Note: no badInputChecker here by purpose as `url` is only a validation
20195   // in browsers, i.e. we can always read out input.value even if it is not valid!
20196   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20197   stringBasedInputType(ctrl);
20198
20199   ctrl.$$parserName = 'url';
20200   ctrl.$validators.url = function(modelValue, viewValue) {
20201     var value = modelValue || viewValue;
20202     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
20203   };
20204 }
20205
20206 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20207   // Note: no badInputChecker here by purpose as `url` is only a validation
20208   // in browsers, i.e. we can always read out input.value even if it is not valid!
20209   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20210   stringBasedInputType(ctrl);
20211
20212   ctrl.$$parserName = 'email';
20213   ctrl.$validators.email = function(modelValue, viewValue) {
20214     var value = modelValue || viewValue;
20215     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
20216   };
20217 }
20218
20219 function radioInputType(scope, element, attr, ctrl) {
20220   // make the name unique, if not defined
20221   if (isUndefined(attr.name)) {
20222     element.attr('name', nextUid());
20223   }
20224
20225   var listener = function(ev) {
20226     if (element[0].checked) {
20227       ctrl.$setViewValue(attr.value, ev && ev.type);
20228     }
20229   };
20230
20231   element.on('click', listener);
20232
20233   ctrl.$render = function() {
20234     var value = attr.value;
20235     element[0].checked = (value == ctrl.$viewValue);
20236   };
20237
20238   attr.$observe('value', ctrl.$render);
20239 }
20240
20241 function parseConstantExpr($parse, context, name, expression, fallback) {
20242   var parseFn;
20243   if (isDefined(expression)) {
20244     parseFn = $parse(expression);
20245     if (!parseFn.constant) {
20246       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
20247                                    '`{1}`.', name, expression);
20248     }
20249     return parseFn(context);
20250   }
20251   return fallback;
20252 }
20253
20254 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
20255   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
20256   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
20257
20258   var listener = function(ev) {
20259     ctrl.$setViewValue(element[0].checked, ev && ev.type);
20260   };
20261
20262   element.on('click', listener);
20263
20264   ctrl.$render = function() {
20265     element[0].checked = ctrl.$viewValue;
20266   };
20267
20268   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
20269   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
20270   // it to a boolean.
20271   ctrl.$isEmpty = function(value) {
20272     return value === false;
20273   };
20274
20275   ctrl.$formatters.push(function(value) {
20276     return equals(value, trueValue);
20277   });
20278
20279   ctrl.$parsers.push(function(value) {
20280     return value ? trueValue : falseValue;
20281   });
20282 }
20283
20284
20285 /**
20286  * @ngdoc directive
20287  * @name textarea
20288  * @restrict E
20289  *
20290  * @description
20291  * HTML textarea element control with angular data-binding. The data-binding and validation
20292  * properties of this element are exactly the same as those of the
20293  * {@link ng.directive:input input element}.
20294  *
20295  * @param {string} ngModel Assignable angular expression to data-bind to.
20296  * @param {string=} name Property name of the form under which the control is published.
20297  * @param {string=} required Sets `required` validation error key if the value is not entered.
20298  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20299  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20300  *    `required` when you want to data-bind to the `required` attribute.
20301  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20302  *    minlength.
20303  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20304  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20305  *    length.
20306  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20307  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20308  *    patterns defined as scope expressions.
20309  * @param {string=} ngChange Angular expression to be executed when input changes due to user
20310  *    interaction with the input element.
20311  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20312  */
20313
20314
20315 /**
20316  * @ngdoc directive
20317  * @name input
20318  * @restrict E
20319  *
20320  * @description
20321  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
20322  * input state control, and validation.
20323  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
20324  *
20325  * <div class="alert alert-warning">
20326  * **Note:** Not every feature offered is available for all input types.
20327  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
20328  * </div>
20329  *
20330  * @param {string} ngModel Assignable angular expression to data-bind to.
20331  * @param {string=} name Property name of the form under which the control is published.
20332  * @param {string=} required Sets `required` validation error key if the value is not entered.
20333  * @param {boolean=} ngRequired Sets `required` attribute if set to true
20334  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20335  *    minlength.
20336  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20337  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20338  *    length.
20339  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20340  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20341  *    patterns defined as scope expressions.
20342  * @param {string=} ngChange Angular expression to be executed when input changes due to user
20343  *    interaction with the input element.
20344  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20345  *    This parameter is ignored for input[type=password] controls, which will never trim the
20346  *    input.
20347  *
20348  * @example
20349     <example name="input-directive" module="inputExample">
20350       <file name="index.html">
20351        <script>
20352           angular.module('inputExample', [])
20353             .controller('ExampleController', ['$scope', function($scope) {
20354               $scope.user = {name: 'guest', last: 'visitor'};
20355             }]);
20356        </script>
20357        <div ng-controller="ExampleController">
20358          <form name="myForm">
20359            User name: <input type="text" name="userName" ng-model="user.name" required>
20360            <span class="error" ng-show="myForm.userName.$error.required">
20361              Required!</span><br>
20362            Last name: <input type="text" name="lastName" ng-model="user.last"
20363              ng-minlength="3" ng-maxlength="10">
20364            <span class="error" ng-show="myForm.lastName.$error.minlength">
20365              Too short!</span>
20366            <span class="error" ng-show="myForm.lastName.$error.maxlength">
20367              Too long!</span><br>
20368          </form>
20369          <hr>
20370          <tt>user = {{user}}</tt><br/>
20371          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
20372          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
20373          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
20374          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
20375          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
20376          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
20377          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
20378          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
20379        </div>
20380       </file>
20381       <file name="protractor.js" type="protractor">
20382         var user = element(by.exactBinding('user'));
20383         var userNameValid = element(by.binding('myForm.userName.$valid'));
20384         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
20385         var lastNameError = element(by.binding('myForm.lastName.$error'));
20386         var formValid = element(by.binding('myForm.$valid'));
20387         var userNameInput = element(by.model('user.name'));
20388         var userLastInput = element(by.model('user.last'));
20389
20390         it('should initialize to model', function() {
20391           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
20392           expect(userNameValid.getText()).toContain('true');
20393           expect(formValid.getText()).toContain('true');
20394         });
20395
20396         it('should be invalid if empty when required', function() {
20397           userNameInput.clear();
20398           userNameInput.sendKeys('');
20399
20400           expect(user.getText()).toContain('{"last":"visitor"}');
20401           expect(userNameValid.getText()).toContain('false');
20402           expect(formValid.getText()).toContain('false');
20403         });
20404
20405         it('should be valid if empty when min length is set', function() {
20406           userLastInput.clear();
20407           userLastInput.sendKeys('');
20408
20409           expect(user.getText()).toContain('{"name":"guest","last":""}');
20410           expect(lastNameValid.getText()).toContain('true');
20411           expect(formValid.getText()).toContain('true');
20412         });
20413
20414         it('should be invalid if less than required min length', function() {
20415           userLastInput.clear();
20416           userLastInput.sendKeys('xx');
20417
20418           expect(user.getText()).toContain('{"name":"guest"}');
20419           expect(lastNameValid.getText()).toContain('false');
20420           expect(lastNameError.getText()).toContain('minlength');
20421           expect(formValid.getText()).toContain('false');
20422         });
20423
20424         it('should be invalid if longer than max length', function() {
20425           userLastInput.clear();
20426           userLastInput.sendKeys('some ridiculously long name');
20427
20428           expect(user.getText()).toContain('{"name":"guest"}');
20429           expect(lastNameValid.getText()).toContain('false');
20430           expect(lastNameError.getText()).toContain('maxlength');
20431           expect(formValid.getText()).toContain('false');
20432         });
20433       </file>
20434     </example>
20435  */
20436 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
20437     function($browser, $sniffer, $filter, $parse) {
20438   return {
20439     restrict: 'E',
20440     require: ['?ngModel'],
20441     link: {
20442       pre: function(scope, element, attr, ctrls) {
20443         if (ctrls[0]) {
20444           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
20445                                                               $browser, $filter, $parse);
20446         }
20447       }
20448     }
20449   };
20450 }];
20451
20452
20453
20454 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
20455 /**
20456  * @ngdoc directive
20457  * @name ngValue
20458  *
20459  * @description
20460  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
20461  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
20462  * the bound value.
20463  *
20464  * `ngValue` is useful when dynamically generating lists of radio buttons using
20465  * {@link ngRepeat `ngRepeat`}, as shown below.
20466  *
20467  * Likewise, `ngValue` can be used to generate `<option>` elements for
20468  * the {@link select `select`} element. In that case however, only strings are supported
20469  * for the `value `attribute, so the resulting `ngModel` will always be a string.
20470  * Support for `select` models with non-string values is available via `ngOptions`.
20471  *
20472  * @element input
20473  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
20474  *   of the `input` element
20475  *
20476  * @example
20477     <example name="ngValue-directive" module="valueExample">
20478       <file name="index.html">
20479        <script>
20480           angular.module('valueExample', [])
20481             .controller('ExampleController', ['$scope', function($scope) {
20482               $scope.names = ['pizza', 'unicorns', 'robots'];
20483               $scope.my = { favorite: 'unicorns' };
20484             }]);
20485        </script>
20486         <form ng-controller="ExampleController">
20487           <h2>Which is your favorite?</h2>
20488             <label ng-repeat="name in names" for="{{name}}">
20489               {{name}}
20490               <input type="radio"
20491                      ng-model="my.favorite"
20492                      ng-value="name"
20493                      id="{{name}}"
20494                      name="favorite">
20495             </label>
20496           <div>You chose {{my.favorite}}</div>
20497         </form>
20498       </file>
20499       <file name="protractor.js" type="protractor">
20500         var favorite = element(by.binding('my.favorite'));
20501
20502         it('should initialize to model', function() {
20503           expect(favorite.getText()).toContain('unicorns');
20504         });
20505         it('should bind the values to the inputs', function() {
20506           element.all(by.model('my.favorite')).get(0).click();
20507           expect(favorite.getText()).toContain('pizza');
20508         });
20509       </file>
20510     </example>
20511  */
20512 var ngValueDirective = function() {
20513   return {
20514     restrict: 'A',
20515     priority: 100,
20516     compile: function(tpl, tplAttr) {
20517       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
20518         return function ngValueConstantLink(scope, elm, attr) {
20519           attr.$set('value', scope.$eval(attr.ngValue));
20520         };
20521       } else {
20522         return function ngValueLink(scope, elm, attr) {
20523           scope.$watch(attr.ngValue, function valueWatchAction(value) {
20524             attr.$set('value', value);
20525           });
20526         };
20527       }
20528     }
20529   };
20530 };
20531
20532 /**
20533  * @ngdoc directive
20534  * @name ngBind
20535  * @restrict AC
20536  *
20537  * @description
20538  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
20539  * with the value of a given expression, and to update the text content when the value of that
20540  * expression changes.
20541  *
20542  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
20543  * `{{ expression }}` which is similar but less verbose.
20544  *
20545  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
20546  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
20547  * element attribute, it makes the bindings invisible to the user while the page is loading.
20548  *
20549  * An alternative solution to this problem would be using the
20550  * {@link ng.directive:ngCloak ngCloak} directive.
20551  *
20552  *
20553  * @element ANY
20554  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
20555  *
20556  * @example
20557  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
20558    <example module="bindExample">
20559      <file name="index.html">
20560        <script>
20561          angular.module('bindExample', [])
20562            .controller('ExampleController', ['$scope', function($scope) {
20563              $scope.name = 'Whirled';
20564            }]);
20565        </script>
20566        <div ng-controller="ExampleController">
20567          Enter name: <input type="text" ng-model="name"><br>
20568          Hello <span ng-bind="name"></span>!
20569        </div>
20570      </file>
20571      <file name="protractor.js" type="protractor">
20572        it('should check ng-bind', function() {
20573          var nameInput = element(by.model('name'));
20574
20575          expect(element(by.binding('name')).getText()).toBe('Whirled');
20576          nameInput.clear();
20577          nameInput.sendKeys('world');
20578          expect(element(by.binding('name')).getText()).toBe('world');
20579        });
20580      </file>
20581    </example>
20582  */
20583 var ngBindDirective = ['$compile', function($compile) {
20584   return {
20585     restrict: 'AC',
20586     compile: function ngBindCompile(templateElement) {
20587       $compile.$$addBindingClass(templateElement);
20588       return function ngBindLink(scope, element, attr) {
20589         $compile.$$addBindingInfo(element, attr.ngBind);
20590         element = element[0];
20591         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
20592           element.textContent = value === undefined ? '' : value;
20593         });
20594       };
20595     }
20596   };
20597 }];
20598
20599
20600 /**
20601  * @ngdoc directive
20602  * @name ngBindTemplate
20603  *
20604  * @description
20605  * The `ngBindTemplate` directive specifies that the element
20606  * text content should be replaced with the interpolation of the template
20607  * in the `ngBindTemplate` attribute.
20608  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
20609  * expressions. This directive is needed since some HTML elements
20610  * (such as TITLE and OPTION) cannot contain SPAN elements.
20611  *
20612  * @element ANY
20613  * @param {string} ngBindTemplate template of form
20614  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
20615  *
20616  * @example
20617  * Try it here: enter text in text box and watch the greeting change.
20618    <example module="bindExample">
20619      <file name="index.html">
20620        <script>
20621          angular.module('bindExample', [])
20622            .controller('ExampleController', ['$scope', function($scope) {
20623              $scope.salutation = 'Hello';
20624              $scope.name = 'World';
20625            }]);
20626        </script>
20627        <div ng-controller="ExampleController">
20628         Salutation: <input type="text" ng-model="salutation"><br>
20629         Name: <input type="text" ng-model="name"><br>
20630         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
20631        </div>
20632      </file>
20633      <file name="protractor.js" type="protractor">
20634        it('should check ng-bind', function() {
20635          var salutationElem = element(by.binding('salutation'));
20636          var salutationInput = element(by.model('salutation'));
20637          var nameInput = element(by.model('name'));
20638
20639          expect(salutationElem.getText()).toBe('Hello World!');
20640
20641          salutationInput.clear();
20642          salutationInput.sendKeys('Greetings');
20643          nameInput.clear();
20644          nameInput.sendKeys('user');
20645
20646          expect(salutationElem.getText()).toBe('Greetings user!');
20647        });
20648      </file>
20649    </example>
20650  */
20651 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
20652   return {
20653     compile: function ngBindTemplateCompile(templateElement) {
20654       $compile.$$addBindingClass(templateElement);
20655       return function ngBindTemplateLink(scope, element, attr) {
20656         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
20657         $compile.$$addBindingInfo(element, interpolateFn.expressions);
20658         element = element[0];
20659         attr.$observe('ngBindTemplate', function(value) {
20660           element.textContent = value === undefined ? '' : value;
20661         });
20662       };
20663     }
20664   };
20665 }];
20666
20667
20668 /**
20669  * @ngdoc directive
20670  * @name ngBindHtml
20671  *
20672  * @description
20673  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
20674  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
20675  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
20676  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
20677  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
20678  *
20679  * You may also bypass sanitization for values you know are safe. To do so, bind to
20680  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
20681  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
20682  *
20683  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
20684  * will have an exception (instead of an exploit.)
20685  *
20686  * @element ANY
20687  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
20688  *
20689  * @example
20690
20691    <example module="bindHtmlExample" deps="angular-sanitize.js">
20692      <file name="index.html">
20693        <div ng-controller="ExampleController">
20694         <p ng-bind-html="myHTML"></p>
20695        </div>
20696      </file>
20697
20698      <file name="script.js">
20699        angular.module('bindHtmlExample', ['ngSanitize'])
20700          .controller('ExampleController', ['$scope', function($scope) {
20701            $scope.myHTML =
20702               'I am an <code>HTML</code>string with ' +
20703               '<a href="#">links!</a> and other <em>stuff</em>';
20704          }]);
20705      </file>
20706
20707      <file name="protractor.js" type="protractor">
20708        it('should check ng-bind-html', function() {
20709          expect(element(by.binding('myHTML')).getText()).toBe(
20710              'I am an HTMLstring with links! and other stuff');
20711        });
20712      </file>
20713    </example>
20714  */
20715 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
20716   return {
20717     restrict: 'A',
20718     compile: function ngBindHtmlCompile(tElement, tAttrs) {
20719       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
20720       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
20721         return (value || '').toString();
20722       });
20723       $compile.$$addBindingClass(tElement);
20724
20725       return function ngBindHtmlLink(scope, element, attr) {
20726         $compile.$$addBindingInfo(element, attr.ngBindHtml);
20727
20728         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
20729           // we re-evaluate the expr because we want a TrustedValueHolderType
20730           // for $sce, not a string
20731           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
20732         });
20733       };
20734     }
20735   };
20736 }];
20737
20738 /**
20739  * @ngdoc directive
20740  * @name ngChange
20741  *
20742  * @description
20743  * Evaluate the given expression when the user changes the input.
20744  * The expression is evaluated immediately, unlike the JavaScript onchange event
20745  * which only triggers at the end of a change (usually, when the user leaves the
20746  * form element or presses the return key).
20747  *
20748  * The `ngChange` expression is only evaluated when a change in the input value causes
20749  * a new value to be committed to the model.
20750  *
20751  * It will not be evaluated:
20752  * * if the value returned from the `$parsers` transformation pipeline has not changed
20753  * * if the input has continued to be invalid since the model will stay `null`
20754  * * if the model is changed programmatically and not by a change to the input value
20755  *
20756  *
20757  * Note, this directive requires `ngModel` to be present.
20758  *
20759  * @element input
20760  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
20761  * in input value.
20762  *
20763  * @example
20764  * <example name="ngChange-directive" module="changeExample">
20765  *   <file name="index.html">
20766  *     <script>
20767  *       angular.module('changeExample', [])
20768  *         .controller('ExampleController', ['$scope', function($scope) {
20769  *           $scope.counter = 0;
20770  *           $scope.change = function() {
20771  *             $scope.counter++;
20772  *           };
20773  *         }]);
20774  *     </script>
20775  *     <div ng-controller="ExampleController">
20776  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
20777  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
20778  *       <label for="ng-change-example2">Confirmed</label><br />
20779  *       <tt>debug = {{confirmed}}</tt><br/>
20780  *       <tt>counter = {{counter}}</tt><br/>
20781  *     </div>
20782  *   </file>
20783  *   <file name="protractor.js" type="protractor">
20784  *     var counter = element(by.binding('counter'));
20785  *     var debug = element(by.binding('confirmed'));
20786  *
20787  *     it('should evaluate the expression if changing from view', function() {
20788  *       expect(counter.getText()).toContain('0');
20789  *
20790  *       element(by.id('ng-change-example1')).click();
20791  *
20792  *       expect(counter.getText()).toContain('1');
20793  *       expect(debug.getText()).toContain('true');
20794  *     });
20795  *
20796  *     it('should not evaluate the expression if changing from model', function() {
20797  *       element(by.id('ng-change-example2')).click();
20798
20799  *       expect(counter.getText()).toContain('0');
20800  *       expect(debug.getText()).toContain('true');
20801  *     });
20802  *   </file>
20803  * </example>
20804  */
20805 var ngChangeDirective = valueFn({
20806   restrict: 'A',
20807   require: 'ngModel',
20808   link: function(scope, element, attr, ctrl) {
20809     ctrl.$viewChangeListeners.push(function() {
20810       scope.$eval(attr.ngChange);
20811     });
20812   }
20813 });
20814
20815 function classDirective(name, selector) {
20816   name = 'ngClass' + name;
20817   return ['$animate', function($animate) {
20818     return {
20819       restrict: 'AC',
20820       link: function(scope, element, attr) {
20821         var oldVal;
20822
20823         scope.$watch(attr[name], ngClassWatchAction, true);
20824
20825         attr.$observe('class', function(value) {
20826           ngClassWatchAction(scope.$eval(attr[name]));
20827         });
20828
20829
20830         if (name !== 'ngClass') {
20831           scope.$watch('$index', function($index, old$index) {
20832             // jshint bitwise: false
20833             var mod = $index & 1;
20834             if (mod !== (old$index & 1)) {
20835               var classes = arrayClasses(scope.$eval(attr[name]));
20836               mod === selector ?
20837                 addClasses(classes) :
20838                 removeClasses(classes);
20839             }
20840           });
20841         }
20842
20843         function addClasses(classes) {
20844           var newClasses = digestClassCounts(classes, 1);
20845           attr.$addClass(newClasses);
20846         }
20847
20848         function removeClasses(classes) {
20849           var newClasses = digestClassCounts(classes, -1);
20850           attr.$removeClass(newClasses);
20851         }
20852
20853         function digestClassCounts(classes, count) {
20854           var classCounts = element.data('$classCounts') || {};
20855           var classesToUpdate = [];
20856           forEach(classes, function(className) {
20857             if (count > 0 || classCounts[className]) {
20858               classCounts[className] = (classCounts[className] || 0) + count;
20859               if (classCounts[className] === +(count > 0)) {
20860                 classesToUpdate.push(className);
20861               }
20862             }
20863           });
20864           element.data('$classCounts', classCounts);
20865           return classesToUpdate.join(' ');
20866         }
20867
20868         function updateClasses(oldClasses, newClasses) {
20869           var toAdd = arrayDifference(newClasses, oldClasses);
20870           var toRemove = arrayDifference(oldClasses, newClasses);
20871           toAdd = digestClassCounts(toAdd, 1);
20872           toRemove = digestClassCounts(toRemove, -1);
20873           if (toAdd && toAdd.length) {
20874             $animate.addClass(element, toAdd);
20875           }
20876           if (toRemove && toRemove.length) {
20877             $animate.removeClass(element, toRemove);
20878           }
20879         }
20880
20881         function ngClassWatchAction(newVal) {
20882           if (selector === true || scope.$index % 2 === selector) {
20883             var newClasses = arrayClasses(newVal || []);
20884             if (!oldVal) {
20885               addClasses(newClasses);
20886             } else if (!equals(newVal,oldVal)) {
20887               var oldClasses = arrayClasses(oldVal);
20888               updateClasses(oldClasses, newClasses);
20889             }
20890           }
20891           oldVal = shallowCopy(newVal);
20892         }
20893       }
20894     };
20895
20896     function arrayDifference(tokens1, tokens2) {
20897       var values = [];
20898
20899       outer:
20900       for (var i = 0; i < tokens1.length; i++) {
20901         var token = tokens1[i];
20902         for (var j = 0; j < tokens2.length; j++) {
20903           if (token == tokens2[j]) continue outer;
20904         }
20905         values.push(token);
20906       }
20907       return values;
20908     }
20909
20910     function arrayClasses(classVal) {
20911       if (isArray(classVal)) {
20912         return classVal;
20913       } else if (isString(classVal)) {
20914         return classVal.split(' ');
20915       } else if (isObject(classVal)) {
20916         var classes = [];
20917         forEach(classVal, function(v, k) {
20918           if (v) {
20919             classes = classes.concat(k.split(' '));
20920           }
20921         });
20922         return classes;
20923       }
20924       return classVal;
20925     }
20926   }];
20927 }
20928
20929 /**
20930  * @ngdoc directive
20931  * @name ngClass
20932  * @restrict AC
20933  *
20934  * @description
20935  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
20936  * an expression that represents all classes to be added.
20937  *
20938  * The directive operates in three different ways, depending on which of three types the expression
20939  * evaluates to:
20940  *
20941  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
20942  * names.
20943  *
20944  * 2. If the expression evaluates to an array, each element of the array should be a string that is
20945  * one or more space-delimited class names.
20946  *
20947  * 3. If the expression evaluates to an object, then for each key-value pair of the
20948  * object with a truthy value the corresponding key is used as a class name.
20949  *
20950  * The directive won't add duplicate classes if a particular class was already set.
20951  *
20952  * When the expression changes, the previously added classes are removed and only then the
20953  * new classes are added.
20954  *
20955  * @animations
20956  * **add** - happens just before the class is applied to the elements
20957  *
20958  * **remove** - happens just before the class is removed from the element
20959  *
20960  * @element ANY
20961  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
20962  *   of the evaluation can be a string representing space delimited class
20963  *   names, an array, or a map of class names to boolean values. In the case of a map, the
20964  *   names of the properties whose values are truthy will be added as css classes to the
20965  *   element.
20966  *
20967  * @example Example that demonstrates basic bindings via ngClass directive.
20968    <example>
20969      <file name="index.html">
20970        <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
20971        <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
20972        <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
20973        <input type="checkbox" ng-model="error"> error (apply "red" class)
20974        <hr>
20975        <p ng-class="style">Using String Syntax</p>
20976        <input type="text" ng-model="style" placeholder="Type: bold strike red">
20977        <hr>
20978        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
20979        <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
20980        <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
20981        <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
20982      </file>
20983      <file name="style.css">
20984        .strike {
20985          text-decoration: line-through;
20986        }
20987        .bold {
20988            font-weight: bold;
20989        }
20990        .red {
20991            color: red;
20992        }
20993      </file>
20994      <file name="protractor.js" type="protractor">
20995        var ps = element.all(by.css('p'));
20996
20997        it('should let you toggle the class', function() {
20998
20999          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
21000          expect(ps.first().getAttribute('class')).not.toMatch(/red/);
21001
21002          element(by.model('important')).click();
21003          expect(ps.first().getAttribute('class')).toMatch(/bold/);
21004
21005          element(by.model('error')).click();
21006          expect(ps.first().getAttribute('class')).toMatch(/red/);
21007        });
21008
21009        it('should let you toggle string example', function() {
21010          expect(ps.get(1).getAttribute('class')).toBe('');
21011          element(by.model('style')).clear();
21012          element(by.model('style')).sendKeys('red');
21013          expect(ps.get(1).getAttribute('class')).toBe('red');
21014        });
21015
21016        it('array example should have 3 classes', function() {
21017          expect(ps.last().getAttribute('class')).toBe('');
21018          element(by.model('style1')).sendKeys('bold');
21019          element(by.model('style2')).sendKeys('strike');
21020          element(by.model('style3')).sendKeys('red');
21021          expect(ps.last().getAttribute('class')).toBe('bold strike red');
21022        });
21023      </file>
21024    </example>
21025
21026    ## Animations
21027
21028    The example below demonstrates how to perform animations using ngClass.
21029
21030    <example module="ngAnimate" deps="angular-animate.js" animations="true">
21031      <file name="index.html">
21032       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
21033       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
21034       <br>
21035       <span class="base-class" ng-class="myVar">Sample Text</span>
21036      </file>
21037      <file name="style.css">
21038        .base-class {
21039          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21040          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21041        }
21042
21043        .base-class.my-class {
21044          color: red;
21045          font-size:3em;
21046        }
21047      </file>
21048      <file name="protractor.js" type="protractor">
21049        it('should check ng-class', function() {
21050          expect(element(by.css('.base-class')).getAttribute('class')).not.
21051            toMatch(/my-class/);
21052
21053          element(by.id('setbtn')).click();
21054
21055          expect(element(by.css('.base-class')).getAttribute('class')).
21056            toMatch(/my-class/);
21057
21058          element(by.id('clearbtn')).click();
21059
21060          expect(element(by.css('.base-class')).getAttribute('class')).not.
21061            toMatch(/my-class/);
21062        });
21063      </file>
21064    </example>
21065
21066
21067    ## ngClass and pre-existing CSS3 Transitions/Animations
21068    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
21069    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
21070    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
21071    to view the step by step details of {@link ng.$animate#addClass $animate.addClass} and
21072    {@link ng.$animate#removeClass $animate.removeClass}.
21073  */
21074 var ngClassDirective = classDirective('', true);
21075
21076 /**
21077  * @ngdoc directive
21078  * @name ngClassOdd
21079  * @restrict AC
21080  *
21081  * @description
21082  * The `ngClassOdd` and `ngClassEven` directives work exactly as
21083  * {@link ng.directive:ngClass ngClass}, except they work in
21084  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
21085  *
21086  * This directive can be applied only within the scope of an
21087  * {@link ng.directive:ngRepeat ngRepeat}.
21088  *
21089  * @element ANY
21090  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
21091  *   of the evaluation can be a string representing space delimited class names or an array.
21092  *
21093  * @example
21094    <example>
21095      <file name="index.html">
21096         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
21097           <li ng-repeat="name in names">
21098            <span ng-class-odd="'odd'" ng-class-even="'even'">
21099              {{name}}
21100            </span>
21101           </li>
21102         </ol>
21103      </file>
21104      <file name="style.css">
21105        .odd {
21106          color: red;
21107        }
21108        .even {
21109          color: blue;
21110        }
21111      </file>
21112      <file name="protractor.js" type="protractor">
21113        it('should check ng-class-odd and ng-class-even', function() {
21114          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
21115            toMatch(/odd/);
21116          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
21117            toMatch(/even/);
21118        });
21119      </file>
21120    </example>
21121  */
21122 var ngClassOddDirective = classDirective('Odd', 0);
21123
21124 /**
21125  * @ngdoc directive
21126  * @name ngClassEven
21127  * @restrict AC
21128  *
21129  * @description
21130  * The `ngClassOdd` and `ngClassEven` directives work exactly as
21131  * {@link ng.directive:ngClass ngClass}, except they work in
21132  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
21133  *
21134  * This directive can be applied only within the scope of an
21135  * {@link ng.directive:ngRepeat ngRepeat}.
21136  *
21137  * @element ANY
21138  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
21139  *   result of the evaluation can be a string representing space delimited class names or an array.
21140  *
21141  * @example
21142    <example>
21143      <file name="index.html">
21144         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
21145           <li ng-repeat="name in names">
21146            <span ng-class-odd="'odd'" ng-class-even="'even'">
21147              {{name}} &nbsp; &nbsp; &nbsp;
21148            </span>
21149           </li>
21150         </ol>
21151      </file>
21152      <file name="style.css">
21153        .odd {
21154          color: red;
21155        }
21156        .even {
21157          color: blue;
21158        }
21159      </file>
21160      <file name="protractor.js" type="protractor">
21161        it('should check ng-class-odd and ng-class-even', function() {
21162          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
21163            toMatch(/odd/);
21164          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
21165            toMatch(/even/);
21166        });
21167      </file>
21168    </example>
21169  */
21170 var ngClassEvenDirective = classDirective('Even', 1);
21171
21172 /**
21173  * @ngdoc directive
21174  * @name ngCloak
21175  * @restrict AC
21176  *
21177  * @description
21178  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
21179  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
21180  * directive to avoid the undesirable flicker effect caused by the html template display.
21181  *
21182  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
21183  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
21184  * of the browser view.
21185  *
21186  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
21187  * `angular.min.js`.
21188  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
21189  *
21190  * ```css
21191  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
21192  *   display: none !important;
21193  * }
21194  * ```
21195  *
21196  * When this css rule is loaded by the browser, all html elements (including their children) that
21197  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
21198  * during the compilation of the template it deletes the `ngCloak` element attribute, making
21199  * the compiled element visible.
21200  *
21201  * For the best result, the `angular.js` script must be loaded in the head section of the html
21202  * document; alternatively, the css rule above must be included in the external stylesheet of the
21203  * application.
21204  *
21205  * @element ANY
21206  *
21207  * @example
21208    <example>
21209      <file name="index.html">
21210         <div id="template1" ng-cloak>{{ 'hello' }}</div>
21211         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
21212      </file>
21213      <file name="protractor.js" type="protractor">
21214        it('should remove the template directive and css class', function() {
21215          expect($('#template1').getAttribute('ng-cloak')).
21216            toBeNull();
21217          expect($('#template2').getAttribute('ng-cloak')).
21218            toBeNull();
21219        });
21220      </file>
21221    </example>
21222  *
21223  */
21224 var ngCloakDirective = ngDirective({
21225   compile: function(element, attr) {
21226     attr.$set('ngCloak', undefined);
21227     element.removeClass('ng-cloak');
21228   }
21229 });
21230
21231 /**
21232  * @ngdoc directive
21233  * @name ngController
21234  *
21235  * @description
21236  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
21237  * supports the principles behind the Model-View-Controller design pattern.
21238  *
21239  * MVC components in angular:
21240  *
21241  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
21242  *   are accessed through bindings.
21243  * * View — The template (HTML with data bindings) that is rendered into the View.
21244  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
21245  *   logic behind the application to decorate the scope with functions and values
21246  *
21247  * Note that you can also attach controllers to the DOM by declaring it in a route definition
21248  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
21249  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
21250  * and executed twice.
21251  *
21252  * @element ANY
21253  * @scope
21254  * @priority 500
21255  * @param {expression} ngController Name of a constructor function registered with the current
21256  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
21257  * that on the current scope evaluates to a constructor function.
21258  *
21259  * The controller instance can be published into a scope property by specifying
21260  * `ng-controller="as propertyName"`.
21261  *
21262  * If the current `$controllerProvider` is configured to use globals (via
21263  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
21264  * also be the name of a globally accessible constructor function (not recommended).
21265  *
21266  * @example
21267  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
21268  * greeting are methods declared on the controller (see source tab). These methods can
21269  * easily be called from the angular markup. Any changes to the data are automatically reflected
21270  * in the View without the need for a manual update.
21271  *
21272  * Two different declaration styles are included below:
21273  *
21274  * * one binds methods and properties directly onto the controller using `this`:
21275  * `ng-controller="SettingsController1 as settings"`
21276  * * one injects `$scope` into the controller:
21277  * `ng-controller="SettingsController2"`
21278  *
21279  * The second option is more common in the Angular community, and is generally used in boilerplates
21280  * and in this guide. However, there are advantages to binding properties directly to the controller
21281  * and avoiding scope.
21282  *
21283  * * Using `controller as` makes it obvious which controller you are accessing in the template when
21284  * multiple controllers apply to an element.
21285  * * If you are writing your controllers as classes you have easier access to the properties and
21286  * methods, which will appear on the scope, from inside the controller code.
21287  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
21288  * inheritance masking primitives.
21289  *
21290  * This example demonstrates the `controller as` syntax.
21291  *
21292  * <example name="ngControllerAs" module="controllerAsExample">
21293  *   <file name="index.html">
21294  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
21295  *      Name: <input type="text" ng-model="settings.name"/>
21296  *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
21297  *      Contact:
21298  *      <ul>
21299  *        <li ng-repeat="contact in settings.contacts">
21300  *          <select ng-model="contact.type">
21301  *             <option>phone</option>
21302  *             <option>email</option>
21303  *          </select>
21304  *          <input type="text" ng-model="contact.value"/>
21305  *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
21306  *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
21307  *        </li>
21308  *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
21309  *     </ul>
21310  *    </div>
21311  *   </file>
21312  *   <file name="app.js">
21313  *    angular.module('controllerAsExample', [])
21314  *      .controller('SettingsController1', SettingsController1);
21315  *
21316  *    function SettingsController1() {
21317  *      this.name = "John Smith";
21318  *      this.contacts = [
21319  *        {type: 'phone', value: '408 555 1212'},
21320  *        {type: 'email', value: 'john.smith@example.org'} ];
21321  *    }
21322  *
21323  *    SettingsController1.prototype.greet = function() {
21324  *      alert(this.name);
21325  *    };
21326  *
21327  *    SettingsController1.prototype.addContact = function() {
21328  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
21329  *    };
21330  *
21331  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
21332  *     var index = this.contacts.indexOf(contactToRemove);
21333  *      this.contacts.splice(index, 1);
21334  *    };
21335  *
21336  *    SettingsController1.prototype.clearContact = function(contact) {
21337  *      contact.type = 'phone';
21338  *      contact.value = '';
21339  *    };
21340  *   </file>
21341  *   <file name="protractor.js" type="protractor">
21342  *     it('should check controller as', function() {
21343  *       var container = element(by.id('ctrl-as-exmpl'));
21344  *         expect(container.element(by.model('settings.name'))
21345  *           .getAttribute('value')).toBe('John Smith');
21346  *
21347  *       var firstRepeat =
21348  *           container.element(by.repeater('contact in settings.contacts').row(0));
21349  *       var secondRepeat =
21350  *           container.element(by.repeater('contact in settings.contacts').row(1));
21351  *
21352  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21353  *           .toBe('408 555 1212');
21354  *
21355  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21356  *           .toBe('john.smith@example.org');
21357  *
21358  *       firstRepeat.element(by.linkText('clear')).click();
21359  *
21360  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21361  *           .toBe('');
21362  *
21363  *       container.element(by.linkText('add')).click();
21364  *
21365  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
21366  *           .element(by.model('contact.value'))
21367  *           .getAttribute('value'))
21368  *           .toBe('yourname@example.org');
21369  *     });
21370  *   </file>
21371  * </example>
21372  *
21373  * This example demonstrates the "attach to `$scope`" style of controller.
21374  *
21375  * <example name="ngController" module="controllerExample">
21376  *  <file name="index.html">
21377  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
21378  *     Name: <input type="text" ng-model="name"/>
21379  *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
21380  *     Contact:
21381  *     <ul>
21382  *       <li ng-repeat="contact in contacts">
21383  *         <select ng-model="contact.type">
21384  *            <option>phone</option>
21385  *            <option>email</option>
21386  *         </select>
21387  *         <input type="text" ng-model="contact.value"/>
21388  *         [ <a href="" ng-click="clearContact(contact)">clear</a>
21389  *         | <a href="" ng-click="removeContact(contact)">X</a> ]
21390  *       </li>
21391  *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
21392  *    </ul>
21393  *   </div>
21394  *  </file>
21395  *  <file name="app.js">
21396  *   angular.module('controllerExample', [])
21397  *     .controller('SettingsController2', ['$scope', SettingsController2]);
21398  *
21399  *   function SettingsController2($scope) {
21400  *     $scope.name = "John Smith";
21401  *     $scope.contacts = [
21402  *       {type:'phone', value:'408 555 1212'},
21403  *       {type:'email', value:'john.smith@example.org'} ];
21404  *
21405  *     $scope.greet = function() {
21406  *       alert($scope.name);
21407  *     };
21408  *
21409  *     $scope.addContact = function() {
21410  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
21411  *     };
21412  *
21413  *     $scope.removeContact = function(contactToRemove) {
21414  *       var index = $scope.contacts.indexOf(contactToRemove);
21415  *       $scope.contacts.splice(index, 1);
21416  *     };
21417  *
21418  *     $scope.clearContact = function(contact) {
21419  *       contact.type = 'phone';
21420  *       contact.value = '';
21421  *     };
21422  *   }
21423  *  </file>
21424  *  <file name="protractor.js" type="protractor">
21425  *    it('should check controller', function() {
21426  *      var container = element(by.id('ctrl-exmpl'));
21427  *
21428  *      expect(container.element(by.model('name'))
21429  *          .getAttribute('value')).toBe('John Smith');
21430  *
21431  *      var firstRepeat =
21432  *          container.element(by.repeater('contact in contacts').row(0));
21433  *      var secondRepeat =
21434  *          container.element(by.repeater('contact in contacts').row(1));
21435  *
21436  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21437  *          .toBe('408 555 1212');
21438  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21439  *          .toBe('john.smith@example.org');
21440  *
21441  *      firstRepeat.element(by.linkText('clear')).click();
21442  *
21443  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21444  *          .toBe('');
21445  *
21446  *      container.element(by.linkText('add')).click();
21447  *
21448  *      expect(container.element(by.repeater('contact in contacts').row(2))
21449  *          .element(by.model('contact.value'))
21450  *          .getAttribute('value'))
21451  *          .toBe('yourname@example.org');
21452  *    });
21453  *  </file>
21454  *</example>
21455
21456  */
21457 var ngControllerDirective = [function() {
21458   return {
21459     restrict: 'A',
21460     scope: true,
21461     controller: '@',
21462     priority: 500
21463   };
21464 }];
21465
21466 /**
21467  * @ngdoc directive
21468  * @name ngCsp
21469  *
21470  * @element html
21471  * @description
21472  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
21473  *
21474  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
21475  *
21476  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
21477  * For Angular to be CSP compatible there are only two things that we need to do differently:
21478  *
21479  * - don't use `Function` constructor to generate optimized value getters
21480  * - don't inject custom stylesheet into the document
21481  *
21482  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
21483  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
21484  * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
21485  * be raised.
21486  *
21487  * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
21488  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
21489  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
21490  *
21491  * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
21492  * autodetection however triggers a CSP error to be logged in the console:
21493  *
21494  * ```
21495  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
21496  * script in the following Content Security Policy directive: "default-src 'self'". Note that
21497  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
21498  * ```
21499  *
21500  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
21501  * directive on the root element of the application or on the `angular.js` script tag, whichever
21502  * appears first in the html document.
21503  *
21504  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
21505  *
21506  * @example
21507  * This example shows how to apply the `ngCsp` directive to the `html` tag.
21508    ```html
21509      <!doctype html>
21510      <html ng-app ng-csp>
21511      ...
21512      ...
21513      </html>
21514    ```
21515   * @example
21516       // Note: the suffix `.csp` in the example name triggers
21517       // csp mode in our http server!
21518       <example name="example.csp" module="cspExample" ng-csp="true">
21519         <file name="index.html">
21520           <div ng-controller="MainController as ctrl">
21521             <div>
21522               <button ng-click="ctrl.inc()" id="inc">Increment</button>
21523               <span id="counter">
21524                 {{ctrl.counter}}
21525               </span>
21526             </div>
21527
21528             <div>
21529               <button ng-click="ctrl.evil()" id="evil">Evil</button>
21530               <span id="evilError">
21531                 {{ctrl.evilError}}
21532               </span>
21533             </div>
21534           </div>
21535         </file>
21536         <file name="script.js">
21537            angular.module('cspExample', [])
21538              .controller('MainController', function() {
21539                 this.counter = 0;
21540                 this.inc = function() {
21541                   this.counter++;
21542                 };
21543                 this.evil = function() {
21544                   // jshint evil:true
21545                   try {
21546                     eval('1+2');
21547                   } catch (e) {
21548                     this.evilError = e.message;
21549                   }
21550                 };
21551               });
21552         </file>
21553         <file name="protractor.js" type="protractor">
21554           var util, webdriver;
21555
21556           var incBtn = element(by.id('inc'));
21557           var counter = element(by.id('counter'));
21558           var evilBtn = element(by.id('evil'));
21559           var evilError = element(by.id('evilError'));
21560
21561           function getAndClearSevereErrors() {
21562             return browser.manage().logs().get('browser').then(function(browserLog) {
21563               return browserLog.filter(function(logEntry) {
21564                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
21565               });
21566             });
21567           }
21568
21569           function clearErrors() {
21570             getAndClearSevereErrors();
21571           }
21572
21573           function expectNoErrors() {
21574             getAndClearSevereErrors().then(function(filteredLog) {
21575               expect(filteredLog.length).toEqual(0);
21576               if (filteredLog.length) {
21577                 console.log('browser console errors: ' + util.inspect(filteredLog));
21578               }
21579             });
21580           }
21581
21582           function expectError(regex) {
21583             getAndClearSevereErrors().then(function(filteredLog) {
21584               var found = false;
21585               filteredLog.forEach(function(log) {
21586                 if (log.message.match(regex)) {
21587                   found = true;
21588                 }
21589               });
21590               if (!found) {
21591                 throw new Error('expected an error that matches ' + regex);
21592               }
21593             });
21594           }
21595
21596           beforeEach(function() {
21597             util = require('util');
21598             webdriver = require('protractor/node_modules/selenium-webdriver');
21599           });
21600
21601           // For now, we only test on Chrome,
21602           // as Safari does not load the page with Protractor's injected scripts,
21603           // and Firefox webdriver always disables content security policy (#6358)
21604           if (browser.params.browser !== 'chrome') {
21605             return;
21606           }
21607
21608           it('should not report errors when the page is loaded', function() {
21609             // clear errors so we are not dependent on previous tests
21610             clearErrors();
21611             // Need to reload the page as the page is already loaded when
21612             // we come here
21613             browser.driver.getCurrentUrl().then(function(url) {
21614               browser.get(url);
21615             });
21616             expectNoErrors();
21617           });
21618
21619           it('should evaluate expressions', function() {
21620             expect(counter.getText()).toEqual('0');
21621             incBtn.click();
21622             expect(counter.getText()).toEqual('1');
21623             expectNoErrors();
21624           });
21625
21626           it('should throw and report an error when using "eval"', function() {
21627             evilBtn.click();
21628             expect(evilError.getText()).toMatch(/Content Security Policy/);
21629             expectError(/Content Security Policy/);
21630           });
21631         </file>
21632       </example>
21633   */
21634
21635 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
21636 // bootstrap the system (before $parse is instantiated), for this reason we just have
21637 // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
21638
21639 /**
21640  * @ngdoc directive
21641  * @name ngClick
21642  *
21643  * @description
21644  * The ngClick directive allows you to specify custom behavior when
21645  * an element is clicked.
21646  *
21647  * @element ANY
21648  * @priority 0
21649  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
21650  * click. ({@link guide/expression#-event- Event object is available as `$event`})
21651  *
21652  * @example
21653    <example>
21654      <file name="index.html">
21655       <button ng-click="count = count + 1" ng-init="count=0">
21656         Increment
21657       </button>
21658       <span>
21659         count: {{count}}
21660       </span>
21661      </file>
21662      <file name="protractor.js" type="protractor">
21663        it('should check ng-click', function() {
21664          expect(element(by.binding('count')).getText()).toMatch('0');
21665          element(by.css('button')).click();
21666          expect(element(by.binding('count')).getText()).toMatch('1');
21667        });
21668      </file>
21669    </example>
21670  */
21671 /*
21672  * A collection of directives that allows creation of custom event handlers that are defined as
21673  * angular expressions and are compiled and executed within the current scope.
21674  */
21675 var ngEventDirectives = {};
21676
21677 // For events that might fire synchronously during DOM manipulation
21678 // we need to execute their event handlers asynchronously using $evalAsync,
21679 // so that they are not executed in an inconsistent state.
21680 var forceAsyncEvents = {
21681   'blur': true,
21682   'focus': true
21683 };
21684 forEach(
21685   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
21686   function(eventName) {
21687     var directiveName = directiveNormalize('ng-' + eventName);
21688     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
21689       return {
21690         restrict: 'A',
21691         compile: function($element, attr) {
21692           // We expose the powerful $event object on the scope that provides access to the Window,
21693           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
21694           // checks at the cost of speed since event handler expressions are not executed as
21695           // frequently as regular change detection.
21696           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
21697           return function ngEventHandler(scope, element) {
21698             element.on(eventName, function(event) {
21699               var callback = function() {
21700                 fn(scope, {$event:event});
21701               };
21702               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
21703                 scope.$evalAsync(callback);
21704               } else {
21705                 scope.$apply(callback);
21706               }
21707             });
21708           };
21709         }
21710       };
21711     }];
21712   }
21713 );
21714
21715 /**
21716  * @ngdoc directive
21717  * @name ngDblclick
21718  *
21719  * @description
21720  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
21721  *
21722  * @element ANY
21723  * @priority 0
21724  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
21725  * a dblclick. (The Event object is available as `$event`)
21726  *
21727  * @example
21728    <example>
21729      <file name="index.html">
21730       <button ng-dblclick="count = count + 1" ng-init="count=0">
21731         Increment (on double click)
21732       </button>
21733       count: {{count}}
21734      </file>
21735    </example>
21736  */
21737
21738
21739 /**
21740  * @ngdoc directive
21741  * @name ngMousedown
21742  *
21743  * @description
21744  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
21745  *
21746  * @element ANY
21747  * @priority 0
21748  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
21749  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
21750  *
21751  * @example
21752    <example>
21753      <file name="index.html">
21754       <button ng-mousedown="count = count + 1" ng-init="count=0">
21755         Increment (on mouse down)
21756       </button>
21757       count: {{count}}
21758      </file>
21759    </example>
21760  */
21761
21762
21763 /**
21764  * @ngdoc directive
21765  * @name ngMouseup
21766  *
21767  * @description
21768  * Specify custom behavior on mouseup event.
21769  *
21770  * @element ANY
21771  * @priority 0
21772  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
21773  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
21774  *
21775  * @example
21776    <example>
21777      <file name="index.html">
21778       <button ng-mouseup="count = count + 1" ng-init="count=0">
21779         Increment (on mouse up)
21780       </button>
21781       count: {{count}}
21782      </file>
21783    </example>
21784  */
21785
21786 /**
21787  * @ngdoc directive
21788  * @name ngMouseover
21789  *
21790  * @description
21791  * Specify custom behavior on mouseover event.
21792  *
21793  * @element ANY
21794  * @priority 0
21795  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
21796  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
21797  *
21798  * @example
21799    <example>
21800      <file name="index.html">
21801       <button ng-mouseover="count = count + 1" ng-init="count=0">
21802         Increment (when mouse is over)
21803       </button>
21804       count: {{count}}
21805      </file>
21806    </example>
21807  */
21808
21809
21810 /**
21811  * @ngdoc directive
21812  * @name ngMouseenter
21813  *
21814  * @description
21815  * Specify custom behavior on mouseenter event.
21816  *
21817  * @element ANY
21818  * @priority 0
21819  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
21820  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
21821  *
21822  * @example
21823    <example>
21824      <file name="index.html">
21825       <button ng-mouseenter="count = count + 1" ng-init="count=0">
21826         Increment (when mouse enters)
21827       </button>
21828       count: {{count}}
21829      </file>
21830    </example>
21831  */
21832
21833
21834 /**
21835  * @ngdoc directive
21836  * @name ngMouseleave
21837  *
21838  * @description
21839  * Specify custom behavior on mouseleave event.
21840  *
21841  * @element ANY
21842  * @priority 0
21843  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
21844  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
21845  *
21846  * @example
21847    <example>
21848      <file name="index.html">
21849       <button ng-mouseleave="count = count + 1" ng-init="count=0">
21850         Increment (when mouse leaves)
21851       </button>
21852       count: {{count}}
21853      </file>
21854    </example>
21855  */
21856
21857
21858 /**
21859  * @ngdoc directive
21860  * @name ngMousemove
21861  *
21862  * @description
21863  * Specify custom behavior on mousemove event.
21864  *
21865  * @element ANY
21866  * @priority 0
21867  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
21868  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
21869  *
21870  * @example
21871    <example>
21872      <file name="index.html">
21873       <button ng-mousemove="count = count + 1" ng-init="count=0">
21874         Increment (when mouse moves)
21875       </button>
21876       count: {{count}}
21877      </file>
21878    </example>
21879  */
21880
21881
21882 /**
21883  * @ngdoc directive
21884  * @name ngKeydown
21885  *
21886  * @description
21887  * Specify custom behavior on keydown event.
21888  *
21889  * @element ANY
21890  * @priority 0
21891  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
21892  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21893  *
21894  * @example
21895    <example>
21896      <file name="index.html">
21897       <input ng-keydown="count = count + 1" ng-init="count=0">
21898       key down count: {{count}}
21899      </file>
21900    </example>
21901  */
21902
21903
21904 /**
21905  * @ngdoc directive
21906  * @name ngKeyup
21907  *
21908  * @description
21909  * Specify custom behavior on keyup event.
21910  *
21911  * @element ANY
21912  * @priority 0
21913  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
21914  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21915  *
21916  * @example
21917    <example>
21918      <file name="index.html">
21919        <p>Typing in the input box below updates the key count</p>
21920        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
21921
21922        <p>Typing in the input box below updates the keycode</p>
21923        <input ng-keyup="event=$event">
21924        <p>event keyCode: {{ event.keyCode }}</p>
21925        <p>event altKey: {{ event.altKey }}</p>
21926      </file>
21927    </example>
21928  */
21929
21930
21931 /**
21932  * @ngdoc directive
21933  * @name ngKeypress
21934  *
21935  * @description
21936  * Specify custom behavior on keypress event.
21937  *
21938  * @element ANY
21939  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
21940  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
21941  * and can be interrogated for keyCode, altKey, etc.)
21942  *
21943  * @example
21944    <example>
21945      <file name="index.html">
21946       <input ng-keypress="count = count + 1" ng-init="count=0">
21947       key press count: {{count}}
21948      </file>
21949    </example>
21950  */
21951
21952
21953 /**
21954  * @ngdoc directive
21955  * @name ngSubmit
21956  *
21957  * @description
21958  * Enables binding angular expressions to onsubmit events.
21959  *
21960  * Additionally it prevents the default action (which for form means sending the request to the
21961  * server and reloading the current page), but only if the form does not contain `action`,
21962  * `data-action`, or `x-action` attributes.
21963  *
21964  * <div class="alert alert-warning">
21965  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
21966  * `ngSubmit` handlers together. See the
21967  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
21968  * for a detailed discussion of when `ngSubmit` may be triggered.
21969  * </div>
21970  *
21971  * @element form
21972  * @priority 0
21973  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
21974  * ({@link guide/expression#-event- Event object is available as `$event`})
21975  *
21976  * @example
21977    <example module="submitExample">
21978      <file name="index.html">
21979       <script>
21980         angular.module('submitExample', [])
21981           .controller('ExampleController', ['$scope', function($scope) {
21982             $scope.list = [];
21983             $scope.text = 'hello';
21984             $scope.submit = function() {
21985               if ($scope.text) {
21986                 $scope.list.push(this.text);
21987                 $scope.text = '';
21988               }
21989             };
21990           }]);
21991       </script>
21992       <form ng-submit="submit()" ng-controller="ExampleController">
21993         Enter text and hit enter:
21994         <input type="text" ng-model="text" name="text" />
21995         <input type="submit" id="submit" value="Submit" />
21996         <pre>list={{list}}</pre>
21997       </form>
21998      </file>
21999      <file name="protractor.js" type="protractor">
22000        it('should check ng-submit', function() {
22001          expect(element(by.binding('list')).getText()).toBe('list=[]');
22002          element(by.css('#submit')).click();
22003          expect(element(by.binding('list')).getText()).toContain('hello');
22004          expect(element(by.model('text')).getAttribute('value')).toBe('');
22005        });
22006        it('should ignore empty strings', function() {
22007          expect(element(by.binding('list')).getText()).toBe('list=[]');
22008          element(by.css('#submit')).click();
22009          element(by.css('#submit')).click();
22010          expect(element(by.binding('list')).getText()).toContain('hello');
22011         });
22012      </file>
22013    </example>
22014  */
22015
22016 /**
22017  * @ngdoc directive
22018  * @name ngFocus
22019  *
22020  * @description
22021  * Specify custom behavior on focus event.
22022  *
22023  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
22024  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
22025  * during an `$apply` to ensure a consistent state.
22026  *
22027  * @element window, input, select, textarea, a
22028  * @priority 0
22029  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
22030  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
22031  *
22032  * @example
22033  * See {@link ng.directive:ngClick ngClick}
22034  */
22035
22036 /**
22037  * @ngdoc directive
22038  * @name ngBlur
22039  *
22040  * @description
22041  * Specify custom behavior on blur event.
22042  *
22043  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
22044  * an element has lost focus.
22045  *
22046  * Note: As the `blur` event is executed synchronously also during DOM manipulations
22047  * (e.g. removing a focussed input),
22048  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
22049  * during an `$apply` to ensure a consistent state.
22050  *
22051  * @element window, input, select, textarea, a
22052  * @priority 0
22053  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
22054  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
22055  *
22056  * @example
22057  * See {@link ng.directive:ngClick ngClick}
22058  */
22059
22060 /**
22061  * @ngdoc directive
22062  * @name ngCopy
22063  *
22064  * @description
22065  * Specify custom behavior on copy event.
22066  *
22067  * @element window, input, select, textarea, a
22068  * @priority 0
22069  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
22070  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
22071  *
22072  * @example
22073    <example>
22074      <file name="index.html">
22075       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
22076       copied: {{copied}}
22077      </file>
22078    </example>
22079  */
22080
22081 /**
22082  * @ngdoc directive
22083  * @name ngCut
22084  *
22085  * @description
22086  * Specify custom behavior on cut event.
22087  *
22088  * @element window, input, select, textarea, a
22089  * @priority 0
22090  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
22091  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
22092  *
22093  * @example
22094    <example>
22095      <file name="index.html">
22096       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
22097       cut: {{cut}}
22098      </file>
22099    </example>
22100  */
22101
22102 /**
22103  * @ngdoc directive
22104  * @name ngPaste
22105  *
22106  * @description
22107  * Specify custom behavior on paste event.
22108  *
22109  * @element window, input, select, textarea, a
22110  * @priority 0
22111  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
22112  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
22113  *
22114  * @example
22115    <example>
22116      <file name="index.html">
22117       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
22118       pasted: {{paste}}
22119      </file>
22120    </example>
22121  */
22122
22123 /**
22124  * @ngdoc directive
22125  * @name ngIf
22126  * @restrict A
22127  *
22128  * @description
22129  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
22130  * {expression}. If the expression assigned to `ngIf` evaluates to a false
22131  * value then the element is removed from the DOM, otherwise a clone of the
22132  * element is reinserted into the DOM.
22133  *
22134  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
22135  * element in the DOM rather than changing its visibility via the `display` css property.  A common
22136  * case when this difference is significant is when using css selectors that rely on an element's
22137  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
22138  *
22139  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
22140  * is created when the element is restored.  The scope created within `ngIf` inherits from
22141  * its parent scope using
22142  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
22143  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
22144  * a javascript primitive defined in the parent scope. In this case any modifications made to the
22145  * variable within the child scope will override (hide) the value in the parent scope.
22146  *
22147  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
22148  * is if an element's class attribute is directly modified after it's compiled, using something like
22149  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
22150  * the added class will be lost because the original compiled state is used to regenerate the element.
22151  *
22152  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
22153  * and `leave` effects.
22154  *
22155  * @animations
22156  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
22157  * leave - happens just before the `ngIf` contents are removed from the DOM
22158  *
22159  * @element ANY
22160  * @scope
22161  * @priority 600
22162  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
22163  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
22164  *     element is added to the DOM tree.
22165  *
22166  * @example
22167   <example module="ngAnimate" deps="angular-animate.js" animations="true">
22168     <file name="index.html">
22169       Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
22170       Show when checked:
22171       <span ng-if="checked" class="animate-if">
22172         This is removed when the checkbox is unchecked.
22173       </span>
22174     </file>
22175     <file name="animations.css">
22176       .animate-if {
22177         background:white;
22178         border:1px solid black;
22179         padding:10px;
22180       }
22181
22182       .animate-if.ng-enter, .animate-if.ng-leave {
22183         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22184         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22185       }
22186
22187       .animate-if.ng-enter,
22188       .animate-if.ng-leave.ng-leave-active {
22189         opacity:0;
22190       }
22191
22192       .animate-if.ng-leave,
22193       .animate-if.ng-enter.ng-enter-active {
22194         opacity:1;
22195       }
22196     </file>
22197   </example>
22198  */
22199 var ngIfDirective = ['$animate', function($animate) {
22200   return {
22201     multiElement: true,
22202     transclude: 'element',
22203     priority: 600,
22204     terminal: true,
22205     restrict: 'A',
22206     $$tlb: true,
22207     link: function($scope, $element, $attr, ctrl, $transclude) {
22208         var block, childScope, previousElements;
22209         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
22210
22211           if (value) {
22212             if (!childScope) {
22213               $transclude(function(clone, newScope) {
22214                 childScope = newScope;
22215                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
22216                 // Note: We only need the first/last node of the cloned nodes.
22217                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
22218                 // by a directive with templateUrl when its template arrives.
22219                 block = {
22220                   clone: clone
22221                 };
22222                 $animate.enter(clone, $element.parent(), $element);
22223               });
22224             }
22225           } else {
22226             if (previousElements) {
22227               previousElements.remove();
22228               previousElements = null;
22229             }
22230             if (childScope) {
22231               childScope.$destroy();
22232               childScope = null;
22233             }
22234             if (block) {
22235               previousElements = getBlockNodes(block.clone);
22236               $animate.leave(previousElements).then(function() {
22237                 previousElements = null;
22238               });
22239               block = null;
22240             }
22241           }
22242         });
22243     }
22244   };
22245 }];
22246
22247 /**
22248  * @ngdoc directive
22249  * @name ngInclude
22250  * @restrict ECA
22251  *
22252  * @description
22253  * Fetches, compiles and includes an external HTML fragment.
22254  *
22255  * By default, the template URL is restricted to the same domain and protocol as the
22256  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
22257  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
22258  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
22259  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
22260  * ng.$sce Strict Contextual Escaping}.
22261  *
22262  * In addition, the browser's
22263  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
22264  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
22265  * policy may further restrict whether the template is successfully loaded.
22266  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
22267  * access on some browsers.
22268  *
22269  * @animations
22270  * enter - animation is used to bring new content into the browser.
22271  * leave - animation is used to animate existing content away.
22272  *
22273  * The enter and leave animation occur concurrently.
22274  *
22275  * @scope
22276  * @priority 400
22277  *
22278  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
22279  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
22280  * @param {string=} onload Expression to evaluate when a new partial is loaded.
22281  *
22282  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
22283  *                  $anchorScroll} to scroll the viewport after the content is loaded.
22284  *
22285  *                  - If the attribute is not set, disable scrolling.
22286  *                  - If the attribute is set without value, enable scrolling.
22287  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
22288  *
22289  * @example
22290   <example module="includeExample" deps="angular-animate.js" animations="true">
22291     <file name="index.html">
22292      <div ng-controller="ExampleController">
22293        <select ng-model="template" ng-options="t.name for t in templates">
22294         <option value="">(blank)</option>
22295        </select>
22296        url of the template: <code>{{template.url}}</code>
22297        <hr/>
22298        <div class="slide-animate-container">
22299          <div class="slide-animate" ng-include="template.url"></div>
22300        </div>
22301      </div>
22302     </file>
22303     <file name="script.js">
22304       angular.module('includeExample', ['ngAnimate'])
22305         .controller('ExampleController', ['$scope', function($scope) {
22306           $scope.templates =
22307             [ { name: 'template1.html', url: 'template1.html'},
22308               { name: 'template2.html', url: 'template2.html'} ];
22309           $scope.template = $scope.templates[0];
22310         }]);
22311      </file>
22312     <file name="template1.html">
22313       Content of template1.html
22314     </file>
22315     <file name="template2.html">
22316       Content of template2.html
22317     </file>
22318     <file name="animations.css">
22319       .slide-animate-container {
22320         position:relative;
22321         background:white;
22322         border:1px solid black;
22323         height:40px;
22324         overflow:hidden;
22325       }
22326
22327       .slide-animate {
22328         padding:10px;
22329       }
22330
22331       .slide-animate.ng-enter, .slide-animate.ng-leave {
22332         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22333         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22334
22335         position:absolute;
22336         top:0;
22337         left:0;
22338         right:0;
22339         bottom:0;
22340         display:block;
22341         padding:10px;
22342       }
22343
22344       .slide-animate.ng-enter {
22345         top:-50px;
22346       }
22347       .slide-animate.ng-enter.ng-enter-active {
22348         top:0;
22349       }
22350
22351       .slide-animate.ng-leave {
22352         top:0;
22353       }
22354       .slide-animate.ng-leave.ng-leave-active {
22355         top:50px;
22356       }
22357     </file>
22358     <file name="protractor.js" type="protractor">
22359       var templateSelect = element(by.model('template'));
22360       var includeElem = element(by.css('[ng-include]'));
22361
22362       it('should load template1.html', function() {
22363         expect(includeElem.getText()).toMatch(/Content of template1.html/);
22364       });
22365
22366       it('should load template2.html', function() {
22367         if (browser.params.browser == 'firefox') {
22368           // Firefox can't handle using selects
22369           // See https://github.com/angular/protractor/issues/480
22370           return;
22371         }
22372         templateSelect.click();
22373         templateSelect.all(by.css('option')).get(2).click();
22374         expect(includeElem.getText()).toMatch(/Content of template2.html/);
22375       });
22376
22377       it('should change to blank', function() {
22378         if (browser.params.browser == 'firefox') {
22379           // Firefox can't handle using selects
22380           return;
22381         }
22382         templateSelect.click();
22383         templateSelect.all(by.css('option')).get(0).click();
22384         expect(includeElem.isPresent()).toBe(false);
22385       });
22386     </file>
22387   </example>
22388  */
22389
22390
22391 /**
22392  * @ngdoc event
22393  * @name ngInclude#$includeContentRequested
22394  * @eventType emit on the scope ngInclude was declared in
22395  * @description
22396  * Emitted every time the ngInclude content is requested.
22397  *
22398  * @param {Object} angularEvent Synthetic event object.
22399  * @param {String} src URL of content to load.
22400  */
22401
22402
22403 /**
22404  * @ngdoc event
22405  * @name ngInclude#$includeContentLoaded
22406  * @eventType emit on the current ngInclude scope
22407  * @description
22408  * Emitted every time the ngInclude content is reloaded.
22409  *
22410  * @param {Object} angularEvent Synthetic event object.
22411  * @param {String} src URL of content to load.
22412  */
22413
22414
22415 /**
22416  * @ngdoc event
22417  * @name ngInclude#$includeContentError
22418  * @eventType emit on the scope ngInclude was declared in
22419  * @description
22420  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
22421  *
22422  * @param {Object} angularEvent Synthetic event object.
22423  * @param {String} src URL of content to load.
22424  */
22425 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
22426                   function($templateRequest,   $anchorScroll,   $animate) {
22427   return {
22428     restrict: 'ECA',
22429     priority: 400,
22430     terminal: true,
22431     transclude: 'element',
22432     controller: angular.noop,
22433     compile: function(element, attr) {
22434       var srcExp = attr.ngInclude || attr.src,
22435           onloadExp = attr.onload || '',
22436           autoScrollExp = attr.autoscroll;
22437
22438       return function(scope, $element, $attr, ctrl, $transclude) {
22439         var changeCounter = 0,
22440             currentScope,
22441             previousElement,
22442             currentElement;
22443
22444         var cleanupLastIncludeContent = function() {
22445           if (previousElement) {
22446             previousElement.remove();
22447             previousElement = null;
22448           }
22449           if (currentScope) {
22450             currentScope.$destroy();
22451             currentScope = null;
22452           }
22453           if (currentElement) {
22454             $animate.leave(currentElement).then(function() {
22455               previousElement = null;
22456             });
22457             previousElement = currentElement;
22458             currentElement = null;
22459           }
22460         };
22461
22462         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
22463           var afterAnimation = function() {
22464             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
22465               $anchorScroll();
22466             }
22467           };
22468           var thisChangeId = ++changeCounter;
22469
22470           if (src) {
22471             //set the 2nd param to true to ignore the template request error so that the inner
22472             //contents and scope can be cleaned up.
22473             $templateRequest(src, true).then(function(response) {
22474               if (thisChangeId !== changeCounter) return;
22475               var newScope = scope.$new();
22476               ctrl.template = response;
22477
22478               // Note: This will also link all children of ng-include that were contained in the original
22479               // html. If that content contains controllers, ... they could pollute/change the scope.
22480               // However, using ng-include on an element with additional content does not make sense...
22481               // Note: We can't remove them in the cloneAttchFn of $transclude as that
22482               // function is called before linking the content, which would apply child
22483               // directives to non existing elements.
22484               var clone = $transclude(newScope, function(clone) {
22485                 cleanupLastIncludeContent();
22486                 $animate.enter(clone, null, $element).then(afterAnimation);
22487               });
22488
22489               currentScope = newScope;
22490               currentElement = clone;
22491
22492               currentScope.$emit('$includeContentLoaded', src);
22493               scope.$eval(onloadExp);
22494             }, function() {
22495               if (thisChangeId === changeCounter) {
22496                 cleanupLastIncludeContent();
22497                 scope.$emit('$includeContentError', src);
22498               }
22499             });
22500             scope.$emit('$includeContentRequested', src);
22501           } else {
22502             cleanupLastIncludeContent();
22503             ctrl.template = null;
22504           }
22505         });
22506       };
22507     }
22508   };
22509 }];
22510
22511 // This directive is called during the $transclude call of the first `ngInclude` directive.
22512 // It will replace and compile the content of the element with the loaded template.
22513 // We need this directive so that the element content is already filled when
22514 // the link function of another directive on the same element as ngInclude
22515 // is called.
22516 var ngIncludeFillContentDirective = ['$compile',
22517   function($compile) {
22518     return {
22519       restrict: 'ECA',
22520       priority: -400,
22521       require: 'ngInclude',
22522       link: function(scope, $element, $attr, ctrl) {
22523         if (/SVG/.test($element[0].toString())) {
22524           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
22525           // support innerHTML, so detect this here and try to generate the contents
22526           // specially.
22527           $element.empty();
22528           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
22529               function namespaceAdaptedClone(clone) {
22530             $element.append(clone);
22531           }, {futureParentElement: $element});
22532           return;
22533         }
22534
22535         $element.html(ctrl.template);
22536         $compile($element.contents())(scope);
22537       }
22538     };
22539   }];
22540
22541 /**
22542  * @ngdoc directive
22543  * @name ngInit
22544  * @restrict AC
22545  *
22546  * @description
22547  * The `ngInit` directive allows you to evaluate an expression in the
22548  * current scope.
22549  *
22550  * <div class="alert alert-error">
22551  * The only appropriate use of `ngInit` is for aliasing special properties of
22552  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
22553  * should use {@link guide/controller controllers} rather than `ngInit`
22554  * to initialize values on a scope.
22555  * </div>
22556  * <div class="alert alert-warning">
22557  * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
22558  * sure you have parenthesis for correct precedence:
22559  * <pre class="prettyprint">
22560  * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
22561  * </pre>
22562  * </div>
22563  *
22564  * @priority 450
22565  *
22566  * @element ANY
22567  * @param {expression} ngInit {@link guide/expression Expression} to eval.
22568  *
22569  * @example
22570    <example module="initExample">
22571      <file name="index.html">
22572    <script>
22573      angular.module('initExample', [])
22574        .controller('ExampleController', ['$scope', function($scope) {
22575          $scope.list = [['a', 'b'], ['c', 'd']];
22576        }]);
22577    </script>
22578    <div ng-controller="ExampleController">
22579      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
22580        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
22581           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
22582        </div>
22583      </div>
22584    </div>
22585      </file>
22586      <file name="protractor.js" type="protractor">
22587        it('should alias index positions', function() {
22588          var elements = element.all(by.css('.example-init'));
22589          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
22590          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
22591          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
22592          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
22593        });
22594      </file>
22595    </example>
22596  */
22597 var ngInitDirective = ngDirective({
22598   priority: 450,
22599   compile: function() {
22600     return {
22601       pre: function(scope, element, attrs) {
22602         scope.$eval(attrs.ngInit);
22603       }
22604     };
22605   }
22606 });
22607
22608 /**
22609  * @ngdoc directive
22610  * @name ngList
22611  *
22612  * @description
22613  * Text input that converts between a delimited string and an array of strings. The default
22614  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
22615  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
22616  *
22617  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
22618  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
22619  *   list item is respected. This implies that the user of the directive is responsible for
22620  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
22621  *   tab or newline character.
22622  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
22623  *   when joining the list items back together) and whitespace around each list item is stripped
22624  *   before it is added to the model.
22625  *
22626  * ### Example with Validation
22627  *
22628  * <example name="ngList-directive" module="listExample">
22629  *   <file name="app.js">
22630  *      angular.module('listExample', [])
22631  *        .controller('ExampleController', ['$scope', function($scope) {
22632  *          $scope.names = ['morpheus', 'neo', 'trinity'];
22633  *        }]);
22634  *   </file>
22635  *   <file name="index.html">
22636  *    <form name="myForm" ng-controller="ExampleController">
22637  *      List: <input name="namesInput" ng-model="names" ng-list required>
22638  *      <span class="error" ng-show="myForm.namesInput.$error.required">
22639  *        Required!</span>
22640  *      <br>
22641  *      <tt>names = {{names}}</tt><br/>
22642  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
22643  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
22644  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22645  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22646  *     </form>
22647  *   </file>
22648  *   <file name="protractor.js" type="protractor">
22649  *     var listInput = element(by.model('names'));
22650  *     var names = element(by.exactBinding('names'));
22651  *     var valid = element(by.binding('myForm.namesInput.$valid'));
22652  *     var error = element(by.css('span.error'));
22653  *
22654  *     it('should initialize to model', function() {
22655  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
22656  *       expect(valid.getText()).toContain('true');
22657  *       expect(error.getCssValue('display')).toBe('none');
22658  *     });
22659  *
22660  *     it('should be invalid if empty', function() {
22661  *       listInput.clear();
22662  *       listInput.sendKeys('');
22663  *
22664  *       expect(names.getText()).toContain('');
22665  *       expect(valid.getText()).toContain('false');
22666  *       expect(error.getCssValue('display')).not.toBe('none');
22667  *     });
22668  *   </file>
22669  * </example>
22670  *
22671  * ### Example - splitting on whitespace
22672  * <example name="ngList-directive-newlines">
22673  *   <file name="index.html">
22674  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
22675  *    <pre>{{ list | json }}</pre>
22676  *   </file>
22677  *   <file name="protractor.js" type="protractor">
22678  *     it("should split the text by newlines", function() {
22679  *       var listInput = element(by.model('list'));
22680  *       var output = element(by.binding('list | json'));
22681  *       listInput.sendKeys('abc\ndef\nghi');
22682  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
22683  *     });
22684  *   </file>
22685  * </example>
22686  *
22687  * @element input
22688  * @param {string=} ngList optional delimiter that should be used to split the value.
22689  */
22690 var ngListDirective = function() {
22691   return {
22692     restrict: 'A',
22693     priority: 100,
22694     require: 'ngModel',
22695     link: function(scope, element, attr, ctrl) {
22696       // We want to control whitespace trimming so we use this convoluted approach
22697       // to access the ngList attribute, which doesn't pre-trim the attribute
22698       var ngList = element.attr(attr.$attr.ngList) || ', ';
22699       var trimValues = attr.ngTrim !== 'false';
22700       var separator = trimValues ? trim(ngList) : ngList;
22701
22702       var parse = function(viewValue) {
22703         // If the viewValue is invalid (say required but empty) it will be `undefined`
22704         if (isUndefined(viewValue)) return;
22705
22706         var list = [];
22707
22708         if (viewValue) {
22709           forEach(viewValue.split(separator), function(value) {
22710             if (value) list.push(trimValues ? trim(value) : value);
22711           });
22712         }
22713
22714         return list;
22715       };
22716
22717       ctrl.$parsers.push(parse);
22718       ctrl.$formatters.push(function(value) {
22719         if (isArray(value)) {
22720           return value.join(ngList);
22721         }
22722
22723         return undefined;
22724       });
22725
22726       // Override the standard $isEmpty because an empty array means the input is empty.
22727       ctrl.$isEmpty = function(value) {
22728         return !value || !value.length;
22729       };
22730     }
22731   };
22732 };
22733
22734 /* global VALID_CLASS: true,
22735   INVALID_CLASS: true,
22736   PRISTINE_CLASS: true,
22737   DIRTY_CLASS: true,
22738   UNTOUCHED_CLASS: true,
22739   TOUCHED_CLASS: true,
22740 */
22741
22742 var VALID_CLASS = 'ng-valid',
22743     INVALID_CLASS = 'ng-invalid',
22744     PRISTINE_CLASS = 'ng-pristine',
22745     DIRTY_CLASS = 'ng-dirty',
22746     UNTOUCHED_CLASS = 'ng-untouched',
22747     TOUCHED_CLASS = 'ng-touched',
22748     PENDING_CLASS = 'ng-pending';
22749
22750 var ngModelMinErr = minErr('ngModel');
22751
22752 /**
22753  * @ngdoc type
22754  * @name ngModel.NgModelController
22755  *
22756  * @property {string} $viewValue Actual string value in the view.
22757  * @property {*} $modelValue The value in the model that the control is bound to.
22758  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
22759        the control reads value from the DOM. The functions are called in array order, each passing
22760        its return value through to the next. The last return value is forwarded to the
22761        {@link ngModel.NgModelController#$validators `$validators`} collection.
22762
22763 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
22764 `$viewValue`}.
22765
22766 Returning `undefined` from a parser means a parse error occurred. In that case,
22767 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
22768 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
22769 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
22770
22771  *
22772  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
22773        the model value changes. The functions are called in reverse array order, each passing the value through to the
22774        next. The last return value is used as the actual DOM value.
22775        Used to format / convert values for display in the control.
22776  * ```js
22777  * function formatter(value) {
22778  *   if (value) {
22779  *     return value.toUpperCase();
22780  *   }
22781  * }
22782  * ngModel.$formatters.push(formatter);
22783  * ```
22784  *
22785  * @property {Object.<string, function>} $validators A collection of validators that are applied
22786  *      whenever the model value changes. The key value within the object refers to the name of the
22787  *      validator while the function refers to the validation operation. The validation operation is
22788  *      provided with the model value as an argument and must return a true or false value depending
22789  *      on the response of that validation.
22790  *
22791  * ```js
22792  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
22793  *   var value = modelValue || viewValue;
22794  *   return /[0-9]+/.test(value) &&
22795  *          /[a-z]+/.test(value) &&
22796  *          /[A-Z]+/.test(value) &&
22797  *          /\W+/.test(value);
22798  * };
22799  * ```
22800  *
22801  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
22802  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
22803  *      is expected to return a promise when it is run during the model validation process. Once the promise
22804  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
22805  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
22806  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
22807  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
22808  *      will only run once all synchronous validators have passed.
22809  *
22810  * Please note that if $http is used then it is important that the server returns a success HTTP response code
22811  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
22812  *
22813  * ```js
22814  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
22815  *   var value = modelValue || viewValue;
22816  *
22817  *   // Lookup user by username
22818  *   return $http.get('/api/users/' + value).
22819  *      then(function resolved() {
22820  *        //username exists, this means validation fails
22821  *        return $q.reject('exists');
22822  *      }, function rejected() {
22823  *        //username does not exist, therefore this validation passes
22824  *        return true;
22825  *      });
22826  * };
22827  * ```
22828  *
22829  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
22830  *     view value has changed. It is called with no arguments, and its return value is ignored.
22831  *     This can be used in place of additional $watches against the model value.
22832  *
22833  * @property {Object} $error An object hash with all failing validator ids as keys.
22834  * @property {Object} $pending An object hash with all pending validator ids as keys.
22835  *
22836  * @property {boolean} $untouched True if control has not lost focus yet.
22837  * @property {boolean} $touched True if control has lost focus.
22838  * @property {boolean} $pristine True if user has not interacted with the control yet.
22839  * @property {boolean} $dirty True if user has already interacted with the control.
22840  * @property {boolean} $valid True if there is no error.
22841  * @property {boolean} $invalid True if at least one error on the control.
22842  * @property {string} $name The name attribute of the control.
22843  *
22844  * @description
22845  *
22846  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
22847  * The controller contains services for data-binding, validation, CSS updates, and value formatting
22848  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
22849  * listening to DOM events.
22850  * Such DOM related logic should be provided by other directives which make use of
22851  * `NgModelController` for data-binding to control elements.
22852  * Angular provides this DOM logic for most {@link input `input`} elements.
22853  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
22854  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
22855  *
22856  * @example
22857  * ### Custom Control Example
22858  * This example shows how to use `NgModelController` with a custom control to achieve
22859  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
22860  * collaborate together to achieve the desired result.
22861  *
22862  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
22863  * contents be edited in place by the user.
22864  *
22865  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
22866  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
22867  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
22868  * that content using the `$sce` service.
22869  *
22870  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
22871     <file name="style.css">
22872       [contenteditable] {
22873         border: 1px solid black;
22874         background-color: white;
22875         min-height: 20px;
22876       }
22877
22878       .ng-invalid {
22879         border: 1px solid red;
22880       }
22881
22882     </file>
22883     <file name="script.js">
22884       angular.module('customControl', ['ngSanitize']).
22885         directive('contenteditable', ['$sce', function($sce) {
22886           return {
22887             restrict: 'A', // only activate on element attribute
22888             require: '?ngModel', // get a hold of NgModelController
22889             link: function(scope, element, attrs, ngModel) {
22890               if (!ngModel) return; // do nothing if no ng-model
22891
22892               // Specify how UI should be updated
22893               ngModel.$render = function() {
22894                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
22895               };
22896
22897               // Listen for change events to enable binding
22898               element.on('blur keyup change', function() {
22899                 scope.$evalAsync(read);
22900               });
22901               read(); // initialize
22902
22903               // Write data to the model
22904               function read() {
22905                 var html = element.html();
22906                 // When we clear the content editable the browser leaves a <br> behind
22907                 // If strip-br attribute is provided then we strip this out
22908                 if ( attrs.stripBr && html == '<br>' ) {
22909                   html = '';
22910                 }
22911                 ngModel.$setViewValue(html);
22912               }
22913             }
22914           };
22915         }]);
22916     </file>
22917     <file name="index.html">
22918       <form name="myForm">
22919        <div contenteditable
22920             name="myWidget" ng-model="userContent"
22921             strip-br="true"
22922             required>Change me!</div>
22923         <span ng-show="myForm.myWidget.$error.required">Required!</span>
22924        <hr>
22925        <textarea ng-model="userContent"></textarea>
22926       </form>
22927     </file>
22928     <file name="protractor.js" type="protractor">
22929     it('should data-bind and become invalid', function() {
22930       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
22931         // SafariDriver can't handle contenteditable
22932         // and Firefox driver can't clear contenteditables very well
22933         return;
22934       }
22935       var contentEditable = element(by.css('[contenteditable]'));
22936       var content = 'Change me!';
22937
22938       expect(contentEditable.getText()).toEqual(content);
22939
22940       contentEditable.clear();
22941       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
22942       expect(contentEditable.getText()).toEqual('');
22943       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
22944     });
22945     </file>
22946  * </example>
22947  *
22948  *
22949  */
22950 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
22951     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
22952   this.$viewValue = Number.NaN;
22953   this.$modelValue = Number.NaN;
22954   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
22955   this.$validators = {};
22956   this.$asyncValidators = {};
22957   this.$parsers = [];
22958   this.$formatters = [];
22959   this.$viewChangeListeners = [];
22960   this.$untouched = true;
22961   this.$touched = false;
22962   this.$pristine = true;
22963   this.$dirty = false;
22964   this.$valid = true;
22965   this.$invalid = false;
22966   this.$error = {}; // keep invalid keys here
22967   this.$$success = {}; // keep valid keys here
22968   this.$pending = undefined; // keep pending keys here
22969   this.$name = $interpolate($attr.name || '', false)($scope);
22970
22971
22972   var parsedNgModel = $parse($attr.ngModel),
22973       parsedNgModelAssign = parsedNgModel.assign,
22974       ngModelGet = parsedNgModel,
22975       ngModelSet = parsedNgModelAssign,
22976       pendingDebounce = null,
22977       parserValid,
22978       ctrl = this;
22979
22980   this.$$setOptions = function(options) {
22981     ctrl.$options = options;
22982     if (options && options.getterSetter) {
22983       var invokeModelGetter = $parse($attr.ngModel + '()'),
22984           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
22985
22986       ngModelGet = function($scope) {
22987         var modelValue = parsedNgModel($scope);
22988         if (isFunction(modelValue)) {
22989           modelValue = invokeModelGetter($scope);
22990         }
22991         return modelValue;
22992       };
22993       ngModelSet = function($scope, newValue) {
22994         if (isFunction(parsedNgModel($scope))) {
22995           invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
22996         } else {
22997           parsedNgModelAssign($scope, ctrl.$modelValue);
22998         }
22999       };
23000     } else if (!parsedNgModel.assign) {
23001       throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
23002           $attr.ngModel, startingTag($element));
23003     }
23004   };
23005
23006   /**
23007    * @ngdoc method
23008    * @name ngModel.NgModelController#$render
23009    *
23010    * @description
23011    * Called when the view needs to be updated. It is expected that the user of the ng-model
23012    * directive will implement this method.
23013    *
23014    * The `$render()` method is invoked in the following situations:
23015    *
23016    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
23017    *   committed value then `$render()` is called to update the input control.
23018    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
23019    *   the `$viewValue` are different to last time.
23020    *
23021    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
23022    * `$modelValue` and `$viewValue` are actually different to their previous value. If `$modelValue`
23023    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
23024    * invoked if you only change a property on the objects.
23025    */
23026   this.$render = noop;
23027
23028   /**
23029    * @ngdoc method
23030    * @name ngModel.NgModelController#$isEmpty
23031    *
23032    * @description
23033    * This is called when we need to determine if the value of an input is empty.
23034    *
23035    * For instance, the required directive does this to work out if the input has data or not.
23036    *
23037    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
23038    *
23039    * You can override this for input directives whose concept of being empty is different to the
23040    * default. The `checkboxInputType` directive does this because in its case a value of `false`
23041    * implies empty.
23042    *
23043    * @param {*} value The value of the input to check for emptiness.
23044    * @returns {boolean} True if `value` is "empty".
23045    */
23046   this.$isEmpty = function(value) {
23047     return isUndefined(value) || value === '' || value === null || value !== value;
23048   };
23049
23050   var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
23051       currentValidationRunId = 0;
23052
23053   /**
23054    * @ngdoc method
23055    * @name ngModel.NgModelController#$setValidity
23056    *
23057    * @description
23058    * Change the validity state, and notify the form.
23059    *
23060    * This method can be called within $parsers/$formatters or a custom validation implementation.
23061    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
23062    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
23063    *
23064    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
23065    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
23066    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
23067    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
23068    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
23069    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
23070    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
23071    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
23072    *                          Skipped is used by Angular when validators do not run because of parse errors and
23073    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
23074    */
23075   addSetValidityMethod({
23076     ctrl: this,
23077     $element: $element,
23078     set: function(object, property) {
23079       object[property] = true;
23080     },
23081     unset: function(object, property) {
23082       delete object[property];
23083     },
23084     parentForm: parentForm,
23085     $animate: $animate
23086   });
23087
23088   /**
23089    * @ngdoc method
23090    * @name ngModel.NgModelController#$setPristine
23091    *
23092    * @description
23093    * Sets the control to its pristine state.
23094    *
23095    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
23096    * state (`ng-pristine` class). A model is considered to be pristine when the control
23097    * has not been changed from when first compiled.
23098    */
23099   this.$setPristine = function() {
23100     ctrl.$dirty = false;
23101     ctrl.$pristine = true;
23102     $animate.removeClass($element, DIRTY_CLASS);
23103     $animate.addClass($element, PRISTINE_CLASS);
23104   };
23105
23106   /**
23107    * @ngdoc method
23108    * @name ngModel.NgModelController#$setDirty
23109    *
23110    * @description
23111    * Sets the control to its dirty state.
23112    *
23113    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
23114    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
23115    * from when first compiled.
23116    */
23117   this.$setDirty = function() {
23118     ctrl.$dirty = true;
23119     ctrl.$pristine = false;
23120     $animate.removeClass($element, PRISTINE_CLASS);
23121     $animate.addClass($element, DIRTY_CLASS);
23122     parentForm.$setDirty();
23123   };
23124
23125   /**
23126    * @ngdoc method
23127    * @name ngModel.NgModelController#$setUntouched
23128    *
23129    * @description
23130    * Sets the control to its untouched state.
23131    *
23132    * This method can be called to remove the `ng-touched` class and set the control to its
23133    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
23134    * by default, however this function can be used to restore that state if the model has
23135    * already been touched by the user.
23136    */
23137   this.$setUntouched = function() {
23138     ctrl.$touched = false;
23139     ctrl.$untouched = true;
23140     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
23141   };
23142
23143   /**
23144    * @ngdoc method
23145    * @name ngModel.NgModelController#$setTouched
23146    *
23147    * @description
23148    * Sets the control to its touched state.
23149    *
23150    * This method can be called to remove the `ng-untouched` class and set the control to its
23151    * touched state (`ng-touched` class). A model is considered to be touched when the user has
23152    * first focused the control element and then shifted focus away from the control (blur event).
23153    */
23154   this.$setTouched = function() {
23155     ctrl.$touched = true;
23156     ctrl.$untouched = false;
23157     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
23158   };
23159
23160   /**
23161    * @ngdoc method
23162    * @name ngModel.NgModelController#$rollbackViewValue
23163    *
23164    * @description
23165    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
23166    * which may be caused by a pending debounced event or because the input is waiting for a some
23167    * future event.
23168    *
23169    * If you have an input that uses `ng-model-options` to set up debounced events or events such
23170    * as blur you can have a situation where there is a period when the `$viewValue`
23171    * is out of synch with the ngModel's `$modelValue`.
23172    *
23173    * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
23174    * programmatically before these debounced/future events have resolved/occurred, because Angular's
23175    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
23176    *
23177    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
23178    * input which may have such events pending. This is important in order to make sure that the
23179    * input field will be updated with the new model value and any pending operations are cancelled.
23180    *
23181    * <example name="ng-model-cancel-update" module="cancel-update-example">
23182    *   <file name="app.js">
23183    *     angular.module('cancel-update-example', [])
23184    *
23185    *     .controller('CancelUpdateController', ['$scope', function($scope) {
23186    *       $scope.resetWithCancel = function(e) {
23187    *         if (e.keyCode == 27) {
23188    *           $scope.myForm.myInput1.$rollbackViewValue();
23189    *           $scope.myValue = '';
23190    *         }
23191    *       };
23192    *       $scope.resetWithoutCancel = function(e) {
23193    *         if (e.keyCode == 27) {
23194    *           $scope.myValue = '';
23195    *         }
23196    *       };
23197    *     }]);
23198    *   </file>
23199    *   <file name="index.html">
23200    *     <div ng-controller="CancelUpdateController">
23201    *       <p>Try typing something in each input.  See that the model only updates when you
23202    *          blur off the input.
23203    *        </p>
23204    *        <p>Now see what happens if you start typing then press the Escape key</p>
23205    *
23206    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
23207    *         <p>With $rollbackViewValue()</p>
23208    *         <input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)"><br/>
23209    *         myValue: "{{ myValue }}"
23210    *
23211    *         <p>Without $rollbackViewValue()</p>
23212    *         <input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)"><br/>
23213    *         myValue: "{{ myValue }}"
23214    *       </form>
23215    *     </div>
23216    *   </file>
23217    * </example>
23218    */
23219   this.$rollbackViewValue = function() {
23220     $timeout.cancel(pendingDebounce);
23221     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
23222     ctrl.$render();
23223   };
23224
23225   /**
23226    * @ngdoc method
23227    * @name ngModel.NgModelController#$validate
23228    *
23229    * @description
23230    * Runs each of the registered validators (first synchronous validators and then
23231    * asynchronous validators).
23232    * If the validity changes to invalid, the model will be set to `undefined`,
23233    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
23234    * If the validity changes to valid, it will set the model to the last available valid
23235    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
23236    */
23237   this.$validate = function() {
23238     // ignore $validate before model is initialized
23239     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
23240       return;
23241     }
23242
23243     var viewValue = ctrl.$$lastCommittedViewValue;
23244     // Note: we use the $$rawModelValue as $modelValue might have been
23245     // set to undefined during a view -> model update that found validation
23246     // errors. We can't parse the view here, since that could change
23247     // the model although neither viewValue nor the model on the scope changed
23248     var modelValue = ctrl.$$rawModelValue;
23249
23250     var prevValid = ctrl.$valid;
23251     var prevModelValue = ctrl.$modelValue;
23252
23253     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
23254
23255     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
23256       // If there was no change in validity, don't update the model
23257       // This prevents changing an invalid modelValue to undefined
23258       if (!allowInvalid && prevValid !== allValid) {
23259         // Note: Don't check ctrl.$valid here, as we could have
23260         // external validators (e.g. calculated on the server),
23261         // that just call $setValidity and need the model value
23262         // to calculate their validity.
23263         ctrl.$modelValue = allValid ? modelValue : undefined;
23264
23265         if (ctrl.$modelValue !== prevModelValue) {
23266           ctrl.$$writeModelToScope();
23267         }
23268       }
23269     });
23270
23271   };
23272
23273   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
23274     currentValidationRunId++;
23275     var localValidationRunId = currentValidationRunId;
23276
23277     // check parser error
23278     if (!processParseErrors()) {
23279       validationDone(false);
23280       return;
23281     }
23282     if (!processSyncValidators()) {
23283       validationDone(false);
23284       return;
23285     }
23286     processAsyncValidators();
23287
23288     function processParseErrors() {
23289       var errorKey = ctrl.$$parserName || 'parse';
23290       if (parserValid === undefined) {
23291         setValidity(errorKey, null);
23292       } else {
23293         if (!parserValid) {
23294           forEach(ctrl.$validators, function(v, name) {
23295             setValidity(name, null);
23296           });
23297           forEach(ctrl.$asyncValidators, function(v, name) {
23298             setValidity(name, null);
23299           });
23300         }
23301         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
23302         setValidity(errorKey, parserValid);
23303         return parserValid;
23304       }
23305       return true;
23306     }
23307
23308     function processSyncValidators() {
23309       var syncValidatorsValid = true;
23310       forEach(ctrl.$validators, function(validator, name) {
23311         var result = validator(modelValue, viewValue);
23312         syncValidatorsValid = syncValidatorsValid && result;
23313         setValidity(name, result);
23314       });
23315       if (!syncValidatorsValid) {
23316         forEach(ctrl.$asyncValidators, function(v, name) {
23317           setValidity(name, null);
23318         });
23319         return false;
23320       }
23321       return true;
23322     }
23323
23324     function processAsyncValidators() {
23325       var validatorPromises = [];
23326       var allValid = true;
23327       forEach(ctrl.$asyncValidators, function(validator, name) {
23328         var promise = validator(modelValue, viewValue);
23329         if (!isPromiseLike(promise)) {
23330           throw ngModelMinErr("$asyncValidators",
23331             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
23332         }
23333         setValidity(name, undefined);
23334         validatorPromises.push(promise.then(function() {
23335           setValidity(name, true);
23336         }, function(error) {
23337           allValid = false;
23338           setValidity(name, false);
23339         }));
23340       });
23341       if (!validatorPromises.length) {
23342         validationDone(true);
23343       } else {
23344         $q.all(validatorPromises).then(function() {
23345           validationDone(allValid);
23346         }, noop);
23347       }
23348     }
23349
23350     function setValidity(name, isValid) {
23351       if (localValidationRunId === currentValidationRunId) {
23352         ctrl.$setValidity(name, isValid);
23353       }
23354     }
23355
23356     function validationDone(allValid) {
23357       if (localValidationRunId === currentValidationRunId) {
23358
23359         doneCallback(allValid);
23360       }
23361     }
23362   };
23363
23364   /**
23365    * @ngdoc method
23366    * @name ngModel.NgModelController#$commitViewValue
23367    *
23368    * @description
23369    * Commit a pending update to the `$modelValue`.
23370    *
23371    * Updates may be pending by a debounced event or because the input is waiting for a some future
23372    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
23373    * usually handles calling this in response to input events.
23374    */
23375   this.$commitViewValue = function() {
23376     var viewValue = ctrl.$viewValue;
23377
23378     $timeout.cancel(pendingDebounce);
23379
23380     // If the view value has not changed then we should just exit, except in the case where there is
23381     // a native validator on the element. In this case the validation state may have changed even though
23382     // the viewValue has stayed empty.
23383     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
23384       return;
23385     }
23386     ctrl.$$lastCommittedViewValue = viewValue;
23387
23388     // change to dirty
23389     if (ctrl.$pristine) {
23390       this.$setDirty();
23391     }
23392     this.$$parseAndValidate();
23393   };
23394
23395   this.$$parseAndValidate = function() {
23396     var viewValue = ctrl.$$lastCommittedViewValue;
23397     var modelValue = viewValue;
23398     parserValid = isUndefined(modelValue) ? undefined : true;
23399
23400     if (parserValid) {
23401       for (var i = 0; i < ctrl.$parsers.length; i++) {
23402         modelValue = ctrl.$parsers[i](modelValue);
23403         if (isUndefined(modelValue)) {
23404           parserValid = false;
23405           break;
23406         }
23407       }
23408     }
23409     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
23410       // ctrl.$modelValue has not been touched yet...
23411       ctrl.$modelValue = ngModelGet($scope);
23412     }
23413     var prevModelValue = ctrl.$modelValue;
23414     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
23415     ctrl.$$rawModelValue = modelValue;
23416
23417     if (allowInvalid) {
23418       ctrl.$modelValue = modelValue;
23419       writeToModelIfNeeded();
23420     }
23421
23422     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
23423     // This can happen if e.g. $setViewValue is called from inside a parser
23424     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
23425       if (!allowInvalid) {
23426         // Note: Don't check ctrl.$valid here, as we could have
23427         // external validators (e.g. calculated on the server),
23428         // that just call $setValidity and need the model value
23429         // to calculate their validity.
23430         ctrl.$modelValue = allValid ? modelValue : undefined;
23431         writeToModelIfNeeded();
23432       }
23433     });
23434
23435     function writeToModelIfNeeded() {
23436       if (ctrl.$modelValue !== prevModelValue) {
23437         ctrl.$$writeModelToScope();
23438       }
23439     }
23440   };
23441
23442   this.$$writeModelToScope = function() {
23443     ngModelSet($scope, ctrl.$modelValue);
23444     forEach(ctrl.$viewChangeListeners, function(listener) {
23445       try {
23446         listener();
23447       } catch (e) {
23448         $exceptionHandler(e);
23449       }
23450     });
23451   };
23452
23453   /**
23454    * @ngdoc method
23455    * @name ngModel.NgModelController#$setViewValue
23456    *
23457    * @description
23458    * Update the view value.
23459    *
23460    * This method should be called when an input directive want to change the view value; typically,
23461    * this is done from within a DOM event handler.
23462    *
23463    * For example {@link ng.directive:input input} calls it when the value of the input changes and
23464    * {@link ng.directive:select select} calls it when an option is selected.
23465    *
23466    * If the new `value` is an object (rather than a string or a number), we should make a copy of the
23467    * object before passing it to `$setViewValue`.  This is because `ngModel` does not perform a deep
23468    * watch of objects, it only looks for a change of identity. If you only change the property of
23469    * the object then ngModel will not realise that the object has changed and will not invoke the
23470    * `$parsers` and `$validators` pipelines.
23471    *
23472    * For this reason, you should not change properties of the copy once it has been passed to
23473    * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
23474    *
23475    * When this method is called, the new `value` will be staged for committing through the `$parsers`
23476    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
23477    * value sent directly for processing, finally to be applied to `$modelValue` and then the
23478    * **expression** specified in the `ng-model` attribute.
23479    *
23480    * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
23481    *
23482    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
23483    * and the `default` trigger is not listed, all those actions will remain pending until one of the
23484    * `updateOn` events is triggered on the DOM element.
23485    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
23486    * directive is used with a custom debounce for this particular event.
23487    *
23488    * Note that calling this function does not trigger a `$digest`.
23489    *
23490    * @param {string} value Value from the view.
23491    * @param {string} trigger Event that triggered the update.
23492    */
23493   this.$setViewValue = function(value, trigger) {
23494     ctrl.$viewValue = value;
23495     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
23496       ctrl.$$debounceViewValueCommit(trigger);
23497     }
23498   };
23499
23500   this.$$debounceViewValueCommit = function(trigger) {
23501     var debounceDelay = 0,
23502         options = ctrl.$options,
23503         debounce;
23504
23505     if (options && isDefined(options.debounce)) {
23506       debounce = options.debounce;
23507       if (isNumber(debounce)) {
23508         debounceDelay = debounce;
23509       } else if (isNumber(debounce[trigger])) {
23510         debounceDelay = debounce[trigger];
23511       } else if (isNumber(debounce['default'])) {
23512         debounceDelay = debounce['default'];
23513       }
23514     }
23515
23516     $timeout.cancel(pendingDebounce);
23517     if (debounceDelay) {
23518       pendingDebounce = $timeout(function() {
23519         ctrl.$commitViewValue();
23520       }, debounceDelay);
23521     } else if ($rootScope.$$phase) {
23522       ctrl.$commitViewValue();
23523     } else {
23524       $scope.$apply(function() {
23525         ctrl.$commitViewValue();
23526       });
23527     }
23528   };
23529
23530   // model -> value
23531   // Note: we cannot use a normal scope.$watch as we want to detect the following:
23532   // 1. scope value is 'a'
23533   // 2. user enters 'b'
23534   // 3. ng-change kicks in and reverts scope value to 'a'
23535   //    -> scope value did not change since the last digest as
23536   //       ng-change executes in apply phase
23537   // 4. view should be changed back to 'a'
23538   $scope.$watch(function ngModelWatch() {
23539     var modelValue = ngModelGet($scope);
23540
23541     // if scope model value and ngModel value are out of sync
23542     // TODO(perf): why not move this to the action fn?
23543     if (modelValue !== ctrl.$modelValue &&
23544        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
23545        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
23546     ) {
23547       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
23548       parserValid = undefined;
23549
23550       var formatters = ctrl.$formatters,
23551           idx = formatters.length;
23552
23553       var viewValue = modelValue;
23554       while (idx--) {
23555         viewValue = formatters[idx](viewValue);
23556       }
23557       if (ctrl.$viewValue !== viewValue) {
23558         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
23559         ctrl.$render();
23560
23561         ctrl.$$runValidators(modelValue, viewValue, noop);
23562       }
23563     }
23564
23565     return modelValue;
23566   });
23567 }];
23568
23569
23570 /**
23571  * @ngdoc directive
23572  * @name ngModel
23573  *
23574  * @element input
23575  * @priority 1
23576  *
23577  * @description
23578  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
23579  * property on the scope using {@link ngModel.NgModelController NgModelController},
23580  * which is created and exposed by this directive.
23581  *
23582  * `ngModel` is responsible for:
23583  *
23584  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
23585  *   require.
23586  * - Providing validation behavior (i.e. required, number, email, url).
23587  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
23588  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
23589  * - Registering the control with its parent {@link ng.directive:form form}.
23590  *
23591  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
23592  * current scope. If the property doesn't already exist on this scope, it will be created
23593  * implicitly and added to the scope.
23594  *
23595  * For best practices on using `ngModel`, see:
23596  *
23597  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
23598  *
23599  * For basic examples, how to use `ngModel`, see:
23600  *
23601  *  - {@link ng.directive:input input}
23602  *    - {@link input[text] text}
23603  *    - {@link input[checkbox] checkbox}
23604  *    - {@link input[radio] radio}
23605  *    - {@link input[number] number}
23606  *    - {@link input[email] email}
23607  *    - {@link input[url] url}
23608  *    - {@link input[date] date}
23609  *    - {@link input[datetime-local] datetime-local}
23610  *    - {@link input[time] time}
23611  *    - {@link input[month] month}
23612  *    - {@link input[week] week}
23613  *  - {@link ng.directive:select select}
23614  *  - {@link ng.directive:textarea textarea}
23615  *
23616  * # CSS classes
23617  * The following CSS classes are added and removed on the associated input/select/textarea element
23618  * depending on the validity of the model.
23619  *
23620  *  - `ng-valid`: the model is valid
23621  *  - `ng-invalid`: the model is invalid
23622  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
23623  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
23624  *  - `ng-pristine`: the control hasn't been interacted with yet
23625  *  - `ng-dirty`: the control has been interacted with
23626  *  - `ng-touched`: the control has been blurred
23627  *  - `ng-untouched`: the control hasn't been blurred
23628  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
23629  *
23630  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
23631  *
23632  * ## Animation Hooks
23633  *
23634  * Animations within models are triggered when any of the associated CSS classes are added and removed
23635  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
23636  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
23637  * The animations that are triggered within ngModel are similar to how they work in ngClass and
23638  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
23639  *
23640  * The following example shows a simple way to utilize CSS transitions to style an input element
23641  * that has been rendered as invalid after it has been validated:
23642  *
23643  * <pre>
23644  * //be sure to include ngAnimate as a module to hook into more
23645  * //advanced animations
23646  * .my-input {
23647  *   transition:0.5s linear all;
23648  *   background: white;
23649  * }
23650  * .my-input.ng-invalid {
23651  *   background: red;
23652  *   color:white;
23653  * }
23654  * </pre>
23655  *
23656  * @example
23657  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
23658      <file name="index.html">
23659        <script>
23660         angular.module('inputExample', [])
23661           .controller('ExampleController', ['$scope', function($scope) {
23662             $scope.val = '1';
23663           }]);
23664        </script>
23665        <style>
23666          .my-input {
23667            -webkit-transition:all linear 0.5s;
23668            transition:all linear 0.5s;
23669            background: transparent;
23670          }
23671          .my-input.ng-invalid {
23672            color:white;
23673            background: red;
23674          }
23675        </style>
23676        Update input to see transitions when valid/invalid.
23677        Integer is a valid value.
23678        <form name="testForm" ng-controller="ExampleController">
23679          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
23680        </form>
23681      </file>
23682  * </example>
23683  *
23684  * ## Binding to a getter/setter
23685  *
23686  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
23687  * function that returns a representation of the model when called with zero arguments, and sets
23688  * the internal state of a model when called with an argument. It's sometimes useful to use this
23689  * for models that have an internal representation that's different than what the model exposes
23690  * to the view.
23691  *
23692  * <div class="alert alert-success">
23693  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
23694  * frequently than other parts of your code.
23695  * </div>
23696  *
23697  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
23698  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
23699  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
23700  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
23701  *
23702  * The following example shows how to use `ngModel` with a getter/setter:
23703  *
23704  * @example
23705  * <example name="ngModel-getter-setter" module="getterSetterExample">
23706      <file name="index.html">
23707        <div ng-controller="ExampleController">
23708          <form name="userForm">
23709            Name:
23710            <input type="text" name="userName"
23711                   ng-model="user.name"
23712                   ng-model-options="{ getterSetter: true }" />
23713          </form>
23714          <pre>user.name = <span ng-bind="user.name()"></span></pre>
23715        </div>
23716      </file>
23717      <file name="app.js">
23718        angular.module('getterSetterExample', [])
23719          .controller('ExampleController', ['$scope', function($scope) {
23720            var _name = 'Brian';
23721            $scope.user = {
23722              name: function(newName) {
23723               // Note that newName can be undefined for two reasons:
23724               // 1. Because it is called as a getter and thus called with no arguments
23725               // 2. Because the property should actually be set to undefined. This happens e.g. if the
23726               //    input is invalid
23727               return arguments.length ? (_name = newName) : _name;
23728              }
23729            };
23730          }]);
23731      </file>
23732  * </example>
23733  */
23734 var ngModelDirective = ['$rootScope', function($rootScope) {
23735   return {
23736     restrict: 'A',
23737     require: ['ngModel', '^?form', '^?ngModelOptions'],
23738     controller: NgModelController,
23739     // Prelink needs to run before any input directive
23740     // so that we can set the NgModelOptions in NgModelController
23741     // before anyone else uses it.
23742     priority: 1,
23743     compile: function ngModelCompile(element) {
23744       // Setup initial state of the control
23745       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
23746
23747       return {
23748         pre: function ngModelPreLink(scope, element, attr, ctrls) {
23749           var modelCtrl = ctrls[0],
23750               formCtrl = ctrls[1] || nullFormCtrl;
23751
23752           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
23753
23754           // notify others, especially parent forms
23755           formCtrl.$addControl(modelCtrl);
23756
23757           attr.$observe('name', function(newValue) {
23758             if (modelCtrl.$name !== newValue) {
23759               formCtrl.$$renameControl(modelCtrl, newValue);
23760             }
23761           });
23762
23763           scope.$on('$destroy', function() {
23764             formCtrl.$removeControl(modelCtrl);
23765           });
23766         },
23767         post: function ngModelPostLink(scope, element, attr, ctrls) {
23768           var modelCtrl = ctrls[0];
23769           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
23770             element.on(modelCtrl.$options.updateOn, function(ev) {
23771               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
23772             });
23773           }
23774
23775           element.on('blur', function(ev) {
23776             if (modelCtrl.$touched) return;
23777
23778             if ($rootScope.$$phase) {
23779               scope.$evalAsync(modelCtrl.$setTouched);
23780             } else {
23781               scope.$apply(modelCtrl.$setTouched);
23782             }
23783           });
23784         }
23785       };
23786     }
23787   };
23788 }];
23789
23790 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
23791
23792 /**
23793  * @ngdoc directive
23794  * @name ngModelOptions
23795  *
23796  * @description
23797  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
23798  * events that will trigger a model update and/or a debouncing delay so that the actual update only
23799  * takes place when a timer expires; this timer will be reset after another change takes place.
23800  *
23801  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
23802  * be different than the value in the actual model. This means that if you update the model you
23803  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
23804  * order to make sure it is synchronized with the model and that any debounced action is canceled.
23805  *
23806  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
23807  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
23808  * important because `form` controllers are published to the related scope under the name in their
23809  * `name` attribute.
23810  *
23811  * Any pending changes will take place immediately when an enclosing form is submitted via the
23812  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
23813  * to have access to the updated model.
23814  *
23815  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
23816  *
23817  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
23818  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
23819  *     events using an space delimited list. There is a special event called `default` that
23820  *     matches the default events belonging of the control.
23821  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
23822  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
23823  *     custom value for each event. For example:
23824  *     `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
23825  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
23826  *     not validate correctly instead of the default behavior of setting the model to undefined.
23827  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
23828        `ngModel` as getters/setters.
23829  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
23830  *     `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
23831  *     otherwise the default timezone of the browser will be used.
23832  *
23833  * @example
23834
23835   The following example shows how to override immediate updates. Changes on the inputs within the
23836   form will update the model only when the control loses focus (blur event). If `escape` key is
23837   pressed while the input field is focused, the value is reset to the value in the current model.
23838
23839   <example name="ngModelOptions-directive-blur" module="optionsExample">
23840     <file name="index.html">
23841       <div ng-controller="ExampleController">
23842         <form name="userForm">
23843           Name:
23844           <input type="text" name="userName"
23845                  ng-model="user.name"
23846                  ng-model-options="{ updateOn: 'blur' }"
23847                  ng-keyup="cancel($event)" /><br />
23848
23849           Other data:
23850           <input type="text" ng-model="user.data" /><br />
23851         </form>
23852         <pre>user.name = <span ng-bind="user.name"></span></pre>
23853       </div>
23854     </file>
23855     <file name="app.js">
23856       angular.module('optionsExample', [])
23857         .controller('ExampleController', ['$scope', function($scope) {
23858           $scope.user = { name: 'say', data: '' };
23859
23860           $scope.cancel = function(e) {
23861             if (e.keyCode == 27) {
23862               $scope.userForm.userName.$rollbackViewValue();
23863             }
23864           };
23865         }]);
23866     </file>
23867     <file name="protractor.js" type="protractor">
23868       var model = element(by.binding('user.name'));
23869       var input = element(by.model('user.name'));
23870       var other = element(by.model('user.data'));
23871
23872       it('should allow custom events', function() {
23873         input.sendKeys(' hello');
23874         input.click();
23875         expect(model.getText()).toEqual('say');
23876         other.click();
23877         expect(model.getText()).toEqual('say hello');
23878       });
23879
23880       it('should $rollbackViewValue when model changes', function() {
23881         input.sendKeys(' hello');
23882         expect(input.getAttribute('value')).toEqual('say hello');
23883         input.sendKeys(protractor.Key.ESCAPE);
23884         expect(input.getAttribute('value')).toEqual('say');
23885         other.click();
23886         expect(model.getText()).toEqual('say');
23887       });
23888     </file>
23889   </example>
23890
23891   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
23892   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
23893
23894   <example name="ngModelOptions-directive-debounce" module="optionsExample">
23895     <file name="index.html">
23896       <div ng-controller="ExampleController">
23897         <form name="userForm">
23898           Name:
23899           <input type="text" name="userName"
23900                  ng-model="user.name"
23901                  ng-model-options="{ debounce: 1000 }" />
23902           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
23903         </form>
23904         <pre>user.name = <span ng-bind="user.name"></span></pre>
23905       </div>
23906     </file>
23907     <file name="app.js">
23908       angular.module('optionsExample', [])
23909         .controller('ExampleController', ['$scope', function($scope) {
23910           $scope.user = { name: 'say' };
23911         }]);
23912     </file>
23913   </example>
23914
23915   This one shows how to bind to getter/setters:
23916
23917   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
23918     <file name="index.html">
23919       <div ng-controller="ExampleController">
23920         <form name="userForm">
23921           Name:
23922           <input type="text" name="userName"
23923                  ng-model="user.name"
23924                  ng-model-options="{ getterSetter: true }" />
23925         </form>
23926         <pre>user.name = <span ng-bind="user.name()"></span></pre>
23927       </div>
23928     </file>
23929     <file name="app.js">
23930       angular.module('getterSetterExample', [])
23931         .controller('ExampleController', ['$scope', function($scope) {
23932           var _name = 'Brian';
23933           $scope.user = {
23934             name: function(newName) {
23935               // Note that newName can be undefined for two reasons:
23936               // 1. Because it is called as a getter and thus called with no arguments
23937               // 2. Because the property should actually be set to undefined. This happens e.g. if the
23938               //    input is invalid
23939               return arguments.length ? (_name = newName) : _name;
23940             }
23941           };
23942         }]);
23943     </file>
23944   </example>
23945  */
23946 var ngModelOptionsDirective = function() {
23947   return {
23948     restrict: 'A',
23949     controller: ['$scope', '$attrs', function($scope, $attrs) {
23950       var that = this;
23951       this.$options = $scope.$eval($attrs.ngModelOptions);
23952       // Allow adding/overriding bound events
23953       if (this.$options.updateOn !== undefined) {
23954         this.$options.updateOnDefault = false;
23955         // extract "default" pseudo-event from list of events that can trigger a model update
23956         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
23957           that.$options.updateOnDefault = true;
23958           return ' ';
23959         }));
23960       } else {
23961         this.$options.updateOnDefault = true;
23962       }
23963     }]
23964   };
23965 };
23966
23967
23968
23969 // helper methods
23970 function addSetValidityMethod(context) {
23971   var ctrl = context.ctrl,
23972       $element = context.$element,
23973       classCache = {},
23974       set = context.set,
23975       unset = context.unset,
23976       parentForm = context.parentForm,
23977       $animate = context.$animate;
23978
23979   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
23980
23981   ctrl.$setValidity = setValidity;
23982
23983   function setValidity(validationErrorKey, state, controller) {
23984     if (state === undefined) {
23985       createAndSet('$pending', validationErrorKey, controller);
23986     } else {
23987       unsetAndCleanup('$pending', validationErrorKey, controller);
23988     }
23989     if (!isBoolean(state)) {
23990       unset(ctrl.$error, validationErrorKey, controller);
23991       unset(ctrl.$$success, validationErrorKey, controller);
23992     } else {
23993       if (state) {
23994         unset(ctrl.$error, validationErrorKey, controller);
23995         set(ctrl.$$success, validationErrorKey, controller);
23996       } else {
23997         set(ctrl.$error, validationErrorKey, controller);
23998         unset(ctrl.$$success, validationErrorKey, controller);
23999       }
24000     }
24001     if (ctrl.$pending) {
24002       cachedToggleClass(PENDING_CLASS, true);
24003       ctrl.$valid = ctrl.$invalid = undefined;
24004       toggleValidationCss('', null);
24005     } else {
24006       cachedToggleClass(PENDING_CLASS, false);
24007       ctrl.$valid = isObjectEmpty(ctrl.$error);
24008       ctrl.$invalid = !ctrl.$valid;
24009       toggleValidationCss('', ctrl.$valid);
24010     }
24011
24012     // re-read the state as the set/unset methods could have
24013     // combined state in ctrl.$error[validationError] (used for forms),
24014     // where setting/unsetting only increments/decrements the value,
24015     // and does not replace it.
24016     var combinedState;
24017     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
24018       combinedState = undefined;
24019     } else if (ctrl.$error[validationErrorKey]) {
24020       combinedState = false;
24021     } else if (ctrl.$$success[validationErrorKey]) {
24022       combinedState = true;
24023     } else {
24024       combinedState = null;
24025     }
24026
24027     toggleValidationCss(validationErrorKey, combinedState);
24028     parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
24029   }
24030
24031   function createAndSet(name, value, controller) {
24032     if (!ctrl[name]) {
24033       ctrl[name] = {};
24034     }
24035     set(ctrl[name], value, controller);
24036   }
24037
24038   function unsetAndCleanup(name, value, controller) {
24039     if (ctrl[name]) {
24040       unset(ctrl[name], value, controller);
24041     }
24042     if (isObjectEmpty(ctrl[name])) {
24043       ctrl[name] = undefined;
24044     }
24045   }
24046
24047   function cachedToggleClass(className, switchValue) {
24048     if (switchValue && !classCache[className]) {
24049       $animate.addClass($element, className);
24050       classCache[className] = true;
24051     } else if (!switchValue && classCache[className]) {
24052       $animate.removeClass($element, className);
24053       classCache[className] = false;
24054     }
24055   }
24056
24057   function toggleValidationCss(validationErrorKey, isValid) {
24058     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
24059
24060     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
24061     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
24062   }
24063 }
24064
24065 function isObjectEmpty(obj) {
24066   if (obj) {
24067     for (var prop in obj) {
24068       return false;
24069     }
24070   }
24071   return true;
24072 }
24073
24074 /**
24075  * @ngdoc directive
24076  * @name ngNonBindable
24077  * @restrict AC
24078  * @priority 1000
24079  *
24080  * @description
24081  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
24082  * DOM element. This is useful if the element contains what appears to be Angular directives and
24083  * bindings but which should be ignored by Angular. This could be the case if you have a site that
24084  * displays snippets of code, for instance.
24085  *
24086  * @element ANY
24087  *
24088  * @example
24089  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
24090  * but the one wrapped in `ngNonBindable` is left alone.
24091  *
24092  * @example
24093     <example>
24094       <file name="index.html">
24095         <div>Normal: {{1 + 2}}</div>
24096         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
24097       </file>
24098       <file name="protractor.js" type="protractor">
24099        it('should check ng-non-bindable', function() {
24100          expect(element(by.binding('1 + 2')).getText()).toContain('3');
24101          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
24102        });
24103       </file>
24104     </example>
24105  */
24106 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
24107
24108 /**
24109  * @ngdoc directive
24110  * @name ngPluralize
24111  * @restrict EA
24112  *
24113  * @description
24114  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
24115  * These rules are bundled with angular.js, but can be overridden
24116  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
24117  * by specifying the mappings between
24118  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
24119  * and the strings to be displayed.
24120  *
24121  * # Plural categories and explicit number rules
24122  * There are two
24123  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
24124  * in Angular's default en-US locale: "one" and "other".
24125  *
24126  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
24127  * any number that is not 1), an explicit number rule can only match one number. For example, the
24128  * explicit number rule for "3" matches the number 3. There are examples of plural categories
24129  * and explicit number rules throughout the rest of this documentation.
24130  *
24131  * # Configuring ngPluralize
24132  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
24133  * You can also provide an optional attribute, `offset`.
24134  *
24135  * The value of the `count` attribute can be either a string or an {@link guide/expression
24136  * Angular expression}; these are evaluated on the current scope for its bound value.
24137  *
24138  * The `when` attribute specifies the mappings between plural categories and the actual
24139  * string to be displayed. The value of the attribute should be a JSON object.
24140  *
24141  * The following example shows how to configure ngPluralize:
24142  *
24143  * ```html
24144  * <ng-pluralize count="personCount"
24145                  when="{'0': 'Nobody is viewing.',
24146  *                      'one': '1 person is viewing.',
24147  *                      'other': '{} people are viewing.'}">
24148  * </ng-pluralize>
24149  *```
24150  *
24151  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
24152  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
24153  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
24154  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
24155  * show "a dozen people are viewing".
24156  *
24157  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
24158  * into pluralized strings. In the previous example, Angular will replace `{}` with
24159  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
24160  * for <span ng-non-bindable>{{numberExpression}}</span>.
24161  *
24162  * # Configuring ngPluralize with offset
24163  * The `offset` attribute allows further customization of pluralized text, which can result in
24164  * a better user experience. For example, instead of the message "4 people are viewing this document",
24165  * you might display "John, Kate and 2 others are viewing this document".
24166  * The offset attribute allows you to offset a number by any desired value.
24167  * Let's take a look at an example:
24168  *
24169  * ```html
24170  * <ng-pluralize count="personCount" offset=2
24171  *               when="{'0': 'Nobody is viewing.',
24172  *                      '1': '{{person1}} is viewing.',
24173  *                      '2': '{{person1}} and {{person2}} are viewing.',
24174  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
24175  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
24176  * </ng-pluralize>
24177  * ```
24178  *
24179  * Notice that we are still using two plural categories(one, other), but we added
24180  * three explicit number rules 0, 1 and 2.
24181  * When one person, perhaps John, views the document, "John is viewing" will be shown.
24182  * When three people view the document, no explicit number rule is found, so
24183  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
24184  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
24185  * is shown.
24186  *
24187  * Note that when you specify offsets, you must provide explicit number rules for
24188  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
24189  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
24190  * plural categories "one" and "other".
24191  *
24192  * @param {string|expression} count The variable to be bound to.
24193  * @param {string} when The mapping between plural category to its corresponding strings.
24194  * @param {number=} offset Offset to deduct from the total number.
24195  *
24196  * @example
24197     <example module="pluralizeExample">
24198       <file name="index.html">
24199         <script>
24200           angular.module('pluralizeExample', [])
24201             .controller('ExampleController', ['$scope', function($scope) {
24202               $scope.person1 = 'Igor';
24203               $scope.person2 = 'Misko';
24204               $scope.personCount = 1;
24205             }]);
24206         </script>
24207         <div ng-controller="ExampleController">
24208           Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
24209           Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
24210           Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
24211
24212           <!--- Example with simple pluralization rules for en locale --->
24213           Without Offset:
24214           <ng-pluralize count="personCount"
24215                         when="{'0': 'Nobody is viewing.',
24216                                'one': '1 person is viewing.',
24217                                'other': '{} people are viewing.'}">
24218           </ng-pluralize><br>
24219
24220           <!--- Example with offset --->
24221           With Offset(2):
24222           <ng-pluralize count="personCount" offset=2
24223                         when="{'0': 'Nobody is viewing.',
24224                                '1': '{{person1}} is viewing.',
24225                                '2': '{{person1}} and {{person2}} are viewing.',
24226                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
24227                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
24228           </ng-pluralize>
24229         </div>
24230       </file>
24231       <file name="protractor.js" type="protractor">
24232         it('should show correct pluralized string', function() {
24233           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
24234           var withOffset = element.all(by.css('ng-pluralize')).get(1);
24235           var countInput = element(by.model('personCount'));
24236
24237           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
24238           expect(withOffset.getText()).toEqual('Igor is viewing.');
24239
24240           countInput.clear();
24241           countInput.sendKeys('0');
24242
24243           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
24244           expect(withOffset.getText()).toEqual('Nobody is viewing.');
24245
24246           countInput.clear();
24247           countInput.sendKeys('2');
24248
24249           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
24250           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
24251
24252           countInput.clear();
24253           countInput.sendKeys('3');
24254
24255           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
24256           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
24257
24258           countInput.clear();
24259           countInput.sendKeys('4');
24260
24261           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
24262           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
24263         });
24264         it('should show data-bound names', function() {
24265           var withOffset = element.all(by.css('ng-pluralize')).get(1);
24266           var personCount = element(by.model('personCount'));
24267           var person1 = element(by.model('person1'));
24268           var person2 = element(by.model('person2'));
24269           personCount.clear();
24270           personCount.sendKeys('4');
24271           person1.clear();
24272           person1.sendKeys('Di');
24273           person2.clear();
24274           person2.sendKeys('Vojta');
24275           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
24276         });
24277       </file>
24278     </example>
24279  */
24280 var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
24281   var BRACE = /{}/g,
24282       IS_WHEN = /^when(Minus)?(.+)$/;
24283
24284   return {
24285     restrict: 'EA',
24286     link: function(scope, element, attr) {
24287       var numberExp = attr.count,
24288           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
24289           offset = attr.offset || 0,
24290           whens = scope.$eval(whenExp) || {},
24291           whensExpFns = {},
24292           startSymbol = $interpolate.startSymbol(),
24293           endSymbol = $interpolate.endSymbol(),
24294           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
24295           watchRemover = angular.noop,
24296           lastCount;
24297
24298       forEach(attr, function(expression, attributeName) {
24299         var tmpMatch = IS_WHEN.exec(attributeName);
24300         if (tmpMatch) {
24301           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
24302           whens[whenKey] = element.attr(attr.$attr[attributeName]);
24303         }
24304       });
24305       forEach(whens, function(expression, key) {
24306         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
24307
24308       });
24309
24310       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
24311         var count = parseFloat(newVal);
24312         var countIsNaN = isNaN(count);
24313
24314         if (!countIsNaN && !(count in whens)) {
24315           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
24316           // Otherwise, check it against pluralization rules in $locale service.
24317           count = $locale.pluralCat(count - offset);
24318         }
24319
24320         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
24321         // In JS `NaN !== NaN`, so we have to exlicitly check.
24322         if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
24323           watchRemover();
24324           watchRemover = scope.$watch(whensExpFns[count], updateElementText);
24325           lastCount = count;
24326         }
24327       });
24328
24329       function updateElementText(newText) {
24330         element.text(newText || '');
24331       }
24332     }
24333   };
24334 }];
24335
24336 /**
24337  * @ngdoc directive
24338  * @name ngRepeat
24339  *
24340  * @description
24341  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
24342  * instance gets its own scope, where the given loop variable is set to the current collection item,
24343  * and `$index` is set to the item index or key.
24344  *
24345  * Special properties are exposed on the local scope of each template instance, including:
24346  *
24347  * | Variable  | Type            | Details                                                                     |
24348  * |-----------|-----------------|-----------------------------------------------------------------------------|
24349  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
24350  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
24351  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
24352  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
24353  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
24354  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
24355  *
24356  * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
24357  * This may be useful when, for instance, nesting ngRepeats.
24358  *
24359  * # Iterating over object properties
24360  *
24361  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
24362  * syntax:
24363  *
24364  * ```js
24365  * <div ng-repeat="(key, value) in myObj"> ... </div>
24366  * ```
24367  *
24368  * You need to be aware that the JavaScript specification does not define what order
24369  * it will return the keys for an object. In order to have a guaranteed deterministic order
24370  * for the keys, Angular versions up to and including 1.3 **sort the keys alphabetically**.
24371  *
24372  * If this is not desired, the recommended workaround is to convert your object into an array
24373  * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
24374  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
24375  * or implement a `$watch` on the object yourself.
24376  *
24377  * In version 1.4 we will remove the sorting, since it seems that browsers generally follow the
24378  * strategy of providing keys in the order in which they were defined, although there are exceptions
24379  * when keys are deleted and reinstated.
24380  *
24381  *
24382  * # Tracking and Duplicates
24383  *
24384  * When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
24385  *
24386  * * When an item is added, a new instance of the template is added to the DOM.
24387  * * When an item is removed, its template instance is removed from the DOM.
24388  * * When items are reordered, their respective templates are reordered in the DOM.
24389  *
24390  * By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
24391  * there are duplicates, it is not possible to maintain a one-to-one mapping between collection
24392  * items and DOM elements.
24393  *
24394  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
24395  * with your own using the `track by` expression.
24396  *
24397  * For example, you may track items by the index of each item in the collection, using the
24398  * special scope property `$index`:
24399  * ```html
24400  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
24401  *      {{n}}
24402  *    </div>
24403  * ```
24404  *
24405  * You may use arbitrary expressions in `track by`, including references to custom functions
24406  * on the scope:
24407  * ```html
24408  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
24409  *      {{n}}
24410  *    </div>
24411  * ```
24412  *
24413  * If you are working with objects that have an identifier property, you can track
24414  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
24415  * will not have to rebuild the DOM elements for items it has already rendered, even if the
24416  * JavaScript objects in the collection have been substituted for new ones:
24417  * ```html
24418  *    <div ng-repeat="model in collection track by model.id">
24419  *      {{model.name}}
24420  *    </div>
24421  * ```
24422  *
24423  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
24424  * `$id` function, which tracks items by their identity:
24425  * ```html
24426  *    <div ng-repeat="obj in collection track by $id(obj)">
24427  *      {{obj.prop}}
24428  *    </div>
24429  * ```
24430  *
24431  * # Special repeat start and end points
24432  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
24433  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
24434  * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
24435  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
24436  *
24437  * The example below makes use of this feature:
24438  * ```html
24439  *   <header ng-repeat-start="item in items">
24440  *     Header {{ item }}
24441  *   </header>
24442  *   <div class="body">
24443  *     Body {{ item }}
24444  *   </div>
24445  *   <footer ng-repeat-end>
24446  *     Footer {{ item }}
24447  *   </footer>
24448  * ```
24449  *
24450  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
24451  * ```html
24452  *   <header>
24453  *     Header A
24454  *   </header>
24455  *   <div class="body">
24456  *     Body A
24457  *   </div>
24458  *   <footer>
24459  *     Footer A
24460  *   </footer>
24461  *   <header>
24462  *     Header B
24463  *   </header>
24464  *   <div class="body">
24465  *     Body B
24466  *   </div>
24467  *   <footer>
24468  *     Footer B
24469  *   </footer>
24470  * ```
24471  *
24472  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
24473  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
24474  *
24475  * @animations
24476  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
24477  *
24478  * **.leave** - when an item is removed from the list or when an item is filtered out
24479  *
24480  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
24481  *
24482  * @element ANY
24483  * @scope
24484  * @priority 1000
24485  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
24486  *   formats are currently supported:
24487  *
24488  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
24489  *     is a scope expression giving the collection to enumerate.
24490  *
24491  *     For example: `album in artist.albums`.
24492  *
24493  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
24494  *     and `expression` is the scope expression giving the collection to enumerate.
24495  *
24496  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
24497  *
24498  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
24499  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
24500  *     is specified, ng-repeat associates elements by identity. It is an error to have
24501  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
24502  *     mapped to the same DOM element, which is not possible.)  If filters are used in the expression, they should be
24503  *     applied before the tracking expression.
24504  *
24505  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
24506  *     will be associated by item identity in the array.
24507  *
24508  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
24509  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
24510  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
24511  *     element in the same way in the DOM.
24512  *
24513  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
24514  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
24515  *     property is same.
24516  *
24517  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
24518  *     to items in conjunction with a tracking expression.
24519  *
24520  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
24521  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
24522  *     when a filter is active on the repeater, but the filtered result set is empty.
24523  *
24524  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
24525  *     the items have been processed through the filter.
24526  *
24527  * @example
24528  * This example initializes the scope to a list of names and
24529  * then uses `ngRepeat` to display every person:
24530   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24531     <file name="index.html">
24532       <div ng-init="friends = [
24533         {name:'John', age:25, gender:'boy'},
24534         {name:'Jessie', age:30, gender:'girl'},
24535         {name:'Johanna', age:28, gender:'girl'},
24536         {name:'Joy', age:15, gender:'girl'},
24537         {name:'Mary', age:28, gender:'girl'},
24538         {name:'Peter', age:95, gender:'boy'},
24539         {name:'Sebastian', age:50, gender:'boy'},
24540         {name:'Erika', age:27, gender:'girl'},
24541         {name:'Patrick', age:40, gender:'boy'},
24542         {name:'Samantha', age:60, gender:'girl'}
24543       ]">
24544         I have {{friends.length}} friends. They are:
24545         <input type="search" ng-model="q" placeholder="filter friends..." />
24546         <ul class="example-animate-container">
24547           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
24548             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
24549           </li>
24550           <li class="animate-repeat" ng-if="results.length == 0">
24551             <strong>No results found...</strong>
24552           </li>
24553         </ul>
24554       </div>
24555     </file>
24556     <file name="animations.css">
24557       .example-animate-container {
24558         background:white;
24559         border:1px solid black;
24560         list-style:none;
24561         margin:0;
24562         padding:0 10px;
24563       }
24564
24565       .animate-repeat {
24566         line-height:40px;
24567         list-style:none;
24568         box-sizing:border-box;
24569       }
24570
24571       .animate-repeat.ng-move,
24572       .animate-repeat.ng-enter,
24573       .animate-repeat.ng-leave {
24574         -webkit-transition:all linear 0.5s;
24575         transition:all linear 0.5s;
24576       }
24577
24578       .animate-repeat.ng-leave.ng-leave-active,
24579       .animate-repeat.ng-move,
24580       .animate-repeat.ng-enter {
24581         opacity:0;
24582         max-height:0;
24583       }
24584
24585       .animate-repeat.ng-leave,
24586       .animate-repeat.ng-move.ng-move-active,
24587       .animate-repeat.ng-enter.ng-enter-active {
24588         opacity:1;
24589         max-height:40px;
24590       }
24591     </file>
24592     <file name="protractor.js" type="protractor">
24593       var friends = element.all(by.repeater('friend in friends'));
24594
24595       it('should render initial data set', function() {
24596         expect(friends.count()).toBe(10);
24597         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
24598         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
24599         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
24600         expect(element(by.binding('friends.length')).getText())
24601             .toMatch("I have 10 friends. They are:");
24602       });
24603
24604        it('should update repeater when filter predicate changes', function() {
24605          expect(friends.count()).toBe(10);
24606
24607          element(by.model('q')).sendKeys('ma');
24608
24609          expect(friends.count()).toBe(2);
24610          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
24611          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
24612        });
24613       </file>
24614     </example>
24615  */
24616 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
24617   var NG_REMOVED = '$$NG_REMOVED';
24618   var ngRepeatMinErr = minErr('ngRepeat');
24619
24620   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
24621     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
24622     scope[valueIdentifier] = value;
24623     if (keyIdentifier) scope[keyIdentifier] = key;
24624     scope.$index = index;
24625     scope.$first = (index === 0);
24626     scope.$last = (index === (arrayLength - 1));
24627     scope.$middle = !(scope.$first || scope.$last);
24628     // jshint bitwise: false
24629     scope.$odd = !(scope.$even = (index&1) === 0);
24630     // jshint bitwise: true
24631   };
24632
24633   var getBlockStart = function(block) {
24634     return block.clone[0];
24635   };
24636
24637   var getBlockEnd = function(block) {
24638     return block.clone[block.clone.length - 1];
24639   };
24640
24641
24642   return {
24643     restrict: 'A',
24644     multiElement: true,
24645     transclude: 'element',
24646     priority: 1000,
24647     terminal: true,
24648     $$tlb: true,
24649     compile: function ngRepeatCompile($element, $attr) {
24650       var expression = $attr.ngRepeat;
24651       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
24652
24653       var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
24654
24655       if (!match) {
24656         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
24657             expression);
24658       }
24659
24660       var lhs = match[1];
24661       var rhs = match[2];
24662       var aliasAs = match[3];
24663       var trackByExp = match[4];
24664
24665       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
24666
24667       if (!match) {
24668         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
24669             lhs);
24670       }
24671       var valueIdentifier = match[3] || match[1];
24672       var keyIdentifier = match[2];
24673
24674       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
24675           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
24676         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
24677           aliasAs);
24678       }
24679
24680       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
24681       var hashFnLocals = {$id: hashKey};
24682
24683       if (trackByExp) {
24684         trackByExpGetter = $parse(trackByExp);
24685       } else {
24686         trackByIdArrayFn = function(key, value) {
24687           return hashKey(value);
24688         };
24689         trackByIdObjFn = function(key) {
24690           return key;
24691         };
24692       }
24693
24694       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
24695
24696         if (trackByExpGetter) {
24697           trackByIdExpFn = function(key, value, index) {
24698             // assign key, value, and $index to the locals so that they can be used in hash functions
24699             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
24700             hashFnLocals[valueIdentifier] = value;
24701             hashFnLocals.$index = index;
24702             return trackByExpGetter($scope, hashFnLocals);
24703           };
24704         }
24705
24706         // Store a list of elements from previous run. This is a hash where key is the item from the
24707         // iterator, and the value is objects with following properties.
24708         //   - scope: bound scope
24709         //   - element: previous element.
24710         //   - index: position
24711         //
24712         // We are using no-proto object so that we don't need to guard against inherited props via
24713         // hasOwnProperty.
24714         var lastBlockMap = createMap();
24715
24716         //watch props
24717         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
24718           var index, length,
24719               previousNode = $element[0],     // node that cloned nodes should be inserted after
24720                                               // initialized to the comment node anchor
24721               nextNode,
24722               // Same as lastBlockMap but it has the current state. It will become the
24723               // lastBlockMap on the next iteration.
24724               nextBlockMap = createMap(),
24725               collectionLength,
24726               key, value, // key/value of iteration
24727               trackById,
24728               trackByIdFn,
24729               collectionKeys,
24730               block,       // last object information {scope, element, id}
24731               nextBlockOrder,
24732               elementsToRemove;
24733
24734           if (aliasAs) {
24735             $scope[aliasAs] = collection;
24736           }
24737
24738           if (isArrayLike(collection)) {
24739             collectionKeys = collection;
24740             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
24741           } else {
24742             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
24743             // if object, extract keys, sort them and use to determine order of iteration over obj props
24744             collectionKeys = [];
24745             for (var itemKey in collection) {
24746               if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
24747                 collectionKeys.push(itemKey);
24748               }
24749             }
24750             collectionKeys.sort();
24751           }
24752
24753           collectionLength = collectionKeys.length;
24754           nextBlockOrder = new Array(collectionLength);
24755
24756           // locate existing items
24757           for (index = 0; index < collectionLength; index++) {
24758             key = (collection === collectionKeys) ? index : collectionKeys[index];
24759             value = collection[key];
24760             trackById = trackByIdFn(key, value, index);
24761             if (lastBlockMap[trackById]) {
24762               // found previously seen block
24763               block = lastBlockMap[trackById];
24764               delete lastBlockMap[trackById];
24765               nextBlockMap[trackById] = block;
24766               nextBlockOrder[index] = block;
24767             } else if (nextBlockMap[trackById]) {
24768               // if collision detected. restore lastBlockMap and throw an error
24769               forEach(nextBlockOrder, function(block) {
24770                 if (block && block.scope) lastBlockMap[block.id] = block;
24771               });
24772               throw ngRepeatMinErr('dupes',
24773                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
24774                   expression, trackById, value);
24775             } else {
24776               // new never before seen block
24777               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
24778               nextBlockMap[trackById] = true;
24779             }
24780           }
24781
24782           // remove leftover items
24783           for (var blockKey in lastBlockMap) {
24784             block = lastBlockMap[blockKey];
24785             elementsToRemove = getBlockNodes(block.clone);
24786             $animate.leave(elementsToRemove);
24787             if (elementsToRemove[0].parentNode) {
24788               // if the element was not removed yet because of pending animation, mark it as deleted
24789               // so that we can ignore it later
24790               for (index = 0, length = elementsToRemove.length; index < length; index++) {
24791                 elementsToRemove[index][NG_REMOVED] = true;
24792               }
24793             }
24794             block.scope.$destroy();
24795           }
24796
24797           // we are not using forEach for perf reasons (trying to avoid #call)
24798           for (index = 0; index < collectionLength; index++) {
24799             key = (collection === collectionKeys) ? index : collectionKeys[index];
24800             value = collection[key];
24801             block = nextBlockOrder[index];
24802
24803             if (block.scope) {
24804               // if we have already seen this object, then we need to reuse the
24805               // associated scope/element
24806
24807               nextNode = previousNode;
24808
24809               // skip nodes that are already pending removal via leave animation
24810               do {
24811                 nextNode = nextNode.nextSibling;
24812               } while (nextNode && nextNode[NG_REMOVED]);
24813
24814               if (getBlockStart(block) != nextNode) {
24815                 // existing item which got moved
24816                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
24817               }
24818               previousNode = getBlockEnd(block);
24819               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24820             } else {
24821               // new item which we don't know about
24822               $transclude(function ngRepeatTransclude(clone, scope) {
24823                 block.scope = scope;
24824                 // http://jsperf.com/clone-vs-createcomment
24825                 var endNode = ngRepeatEndComment.cloneNode(false);
24826                 clone[clone.length++] = endNode;
24827
24828                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
24829                 $animate.enter(clone, null, jqLite(previousNode));
24830                 previousNode = endNode;
24831                 // Note: We only need the first/last node of the cloned nodes.
24832                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24833                 // by a directive with templateUrl when its template arrives.
24834                 block.clone = clone;
24835                 nextBlockMap[block.id] = block;
24836                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24837               });
24838             }
24839           }
24840           lastBlockMap = nextBlockMap;
24841         });
24842       };
24843     }
24844   };
24845 }];
24846
24847 var NG_HIDE_CLASS = 'ng-hide';
24848 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24849 /**
24850  * @ngdoc directive
24851  * @name ngShow
24852  *
24853  * @description
24854  * The `ngShow` directive shows or hides the given HTML element based on the expression
24855  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
24856  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
24857  * in AngularJS and sets the display style to none (using an !important flag).
24858  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
24859  *
24860  * ```html
24861  * <!-- when $scope.myValue is truthy (element is visible) -->
24862  * <div ng-show="myValue"></div>
24863  *
24864  * <!-- when $scope.myValue is falsy (element is hidden) -->
24865  * <div ng-show="myValue" class="ng-hide"></div>
24866  * ```
24867  *
24868  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
24869  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
24870  * from the element causing the element not to appear hidden.
24871  *
24872  * ## Why is !important used?
24873  *
24874  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
24875  * can be easily overridden by heavier selectors. For example, something as simple
24876  * as changing the display style on a HTML list item would make hidden elements appear visible.
24877  * This also becomes a bigger issue when dealing with CSS frameworks.
24878  *
24879  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
24880  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
24881  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
24882  *
24883  * ### Overriding `.ng-hide`
24884  *
24885  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24886  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24887  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
24888  * with extra animation classes that can be added.
24889  *
24890  * ```css
24891  * .ng-hide:not(.ng-hide-animate) {
24892  *   /&#42; this is just another form of hiding an element &#42;/
24893  *   display: block!important;
24894  *   position: absolute;
24895  *   top: -9999px;
24896  *   left: -9999px;
24897  * }
24898  * ```
24899  *
24900  * By default you don't need to override in CSS anything and the animations will work around the display style.
24901  *
24902  * ## A note about animations with `ngShow`
24903  *
24904  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
24905  * is true and false. This system works like the animation system present with ngClass except that
24906  * you must also include the !important flag to override the display property
24907  * so that you can perform an animation when the element is hidden during the time of the animation.
24908  *
24909  * ```css
24910  * //
24911  * //a working example can be found at the bottom of this page
24912  * //
24913  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24914  *   /&#42; this is required as of 1.3x to properly
24915  *      apply all styling in a show/hide animation &#42;/
24916  *   transition: 0s linear all;
24917  * }
24918  *
24919  * .my-element.ng-hide-add-active,
24920  * .my-element.ng-hide-remove-active {
24921  *   /&#42; the transition is defined in the active class &#42;/
24922  *   transition: 1s linear all;
24923  * }
24924  *
24925  * .my-element.ng-hide-add { ... }
24926  * .my-element.ng-hide-add.ng-hide-add-active { ... }
24927  * .my-element.ng-hide-remove { ... }
24928  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
24929  * ```
24930  *
24931  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
24932  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
24933  *
24934  * @animations
24935  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
24936  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
24937  *
24938  * @element ANY
24939  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
24940  *     then the element is shown or hidden respectively.
24941  *
24942  * @example
24943   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24944     <file name="index.html">
24945       Click me: <input type="checkbox" ng-model="checked"><br/>
24946       <div>
24947         Show:
24948         <div class="check-element animate-show" ng-show="checked">
24949           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
24950         </div>
24951       </div>
24952       <div>
24953         Hide:
24954         <div class="check-element animate-show" ng-hide="checked">
24955           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
24956         </div>
24957       </div>
24958     </file>
24959     <file name="glyphicons.css">
24960       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
24961     </file>
24962     <file name="animations.css">
24963       .animate-show {
24964         line-height: 20px;
24965         opacity: 1;
24966         padding: 10px;
24967         border: 1px solid black;
24968         background: white;
24969       }
24970
24971       .animate-show.ng-hide-add.ng-hide-add-active,
24972       .animate-show.ng-hide-remove.ng-hide-remove-active {
24973         -webkit-transition: all linear 0.5s;
24974         transition: all linear 0.5s;
24975       }
24976
24977       .animate-show.ng-hide {
24978         line-height: 0;
24979         opacity: 0;
24980         padding: 0 10px;
24981       }
24982
24983       .check-element {
24984         padding: 10px;
24985         border: 1px solid black;
24986         background: white;
24987       }
24988     </file>
24989     <file name="protractor.js" type="protractor">
24990       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
24991       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
24992
24993       it('should check ng-show / ng-hide', function() {
24994         expect(thumbsUp.isDisplayed()).toBeFalsy();
24995         expect(thumbsDown.isDisplayed()).toBeTruthy();
24996
24997         element(by.model('checked')).click();
24998
24999         expect(thumbsUp.isDisplayed()).toBeTruthy();
25000         expect(thumbsDown.isDisplayed()).toBeFalsy();
25001       });
25002     </file>
25003   </example>
25004  */
25005 var ngShowDirective = ['$animate', function($animate) {
25006   return {
25007     restrict: 'A',
25008     multiElement: true,
25009     link: function(scope, element, attr) {
25010       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
25011         // we're adding a temporary, animation-specific class for ng-hide since this way
25012         // we can control when the element is actually displayed on screen without having
25013         // to have a global/greedy CSS selector that breaks when other animations are run.
25014         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
25015         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
25016           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
25017         });
25018       });
25019     }
25020   };
25021 }];
25022
25023
25024 /**
25025  * @ngdoc directive
25026  * @name ngHide
25027  *
25028  * @description
25029  * The `ngHide` directive shows or hides the given HTML element based on the expression
25030  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
25031  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
25032  * in AngularJS and sets the display style to none (using an !important flag).
25033  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
25034  *
25035  * ```html
25036  * <!-- when $scope.myValue is truthy (element is hidden) -->
25037  * <div ng-hide="myValue" class="ng-hide"></div>
25038  *
25039  * <!-- when $scope.myValue is falsy (element is visible) -->
25040  * <div ng-hide="myValue"></div>
25041  * ```
25042  *
25043  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
25044  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
25045  * from the element causing the element not to appear hidden.
25046  *
25047  * ## Why is !important used?
25048  *
25049  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
25050  * can be easily overridden by heavier selectors. For example, something as simple
25051  * as changing the display style on a HTML list item would make hidden elements appear visible.
25052  * This also becomes a bigger issue when dealing with CSS frameworks.
25053  *
25054  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
25055  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
25056  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
25057  *
25058  * ### Overriding `.ng-hide`
25059  *
25060  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
25061  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
25062  * class in CSS:
25063  *
25064  * ```css
25065  * .ng-hide {
25066  *   /&#42; this is just another form of hiding an element &#42;/
25067  *   display: block!important;
25068  *   position: absolute;
25069  *   top: -9999px;
25070  *   left: -9999px;
25071  * }
25072  * ```
25073  *
25074  * By default you don't need to override in CSS anything and the animations will work around the display style.
25075  *
25076  * ## A note about animations with `ngHide`
25077  *
25078  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
25079  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
25080  * CSS class is added and removed for you instead of your own CSS class.
25081  *
25082  * ```css
25083  * //
25084  * //a working example can be found at the bottom of this page
25085  * //
25086  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
25087  *   transition: 0.5s linear all;
25088  * }
25089  *
25090  * .my-element.ng-hide-add { ... }
25091  * .my-element.ng-hide-add.ng-hide-add-active { ... }
25092  * .my-element.ng-hide-remove { ... }
25093  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
25094  * ```
25095  *
25096  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
25097  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
25098  *
25099  * @animations
25100  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
25101  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
25102  *
25103  * @element ANY
25104  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
25105  *     the element is shown or hidden respectively.
25106  *
25107  * @example
25108   <example module="ngAnimate" deps="angular-animate.js" animations="true">
25109     <file name="index.html">
25110       Click me: <input type="checkbox" ng-model="checked"><br/>
25111       <div>
25112         Show:
25113         <div class="check-element animate-hide" ng-show="checked">
25114           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
25115         </div>
25116       </div>
25117       <div>
25118         Hide:
25119         <div class="check-element animate-hide" ng-hide="checked">
25120           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
25121         </div>
25122       </div>
25123     </file>
25124     <file name="glyphicons.css">
25125       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
25126     </file>
25127     <file name="animations.css">
25128       .animate-hide {
25129         -webkit-transition: all linear 0.5s;
25130         transition: all linear 0.5s;
25131         line-height: 20px;
25132         opacity: 1;
25133         padding: 10px;
25134         border: 1px solid black;
25135         background: white;
25136       }
25137
25138       .animate-hide.ng-hide {
25139         line-height: 0;
25140         opacity: 0;
25141         padding: 0 10px;
25142       }
25143
25144       .check-element {
25145         padding: 10px;
25146         border: 1px solid black;
25147         background: white;
25148       }
25149     </file>
25150     <file name="protractor.js" type="protractor">
25151       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
25152       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
25153
25154       it('should check ng-show / ng-hide', function() {
25155         expect(thumbsUp.isDisplayed()).toBeFalsy();
25156         expect(thumbsDown.isDisplayed()).toBeTruthy();
25157
25158         element(by.model('checked')).click();
25159
25160         expect(thumbsUp.isDisplayed()).toBeTruthy();
25161         expect(thumbsDown.isDisplayed()).toBeFalsy();
25162       });
25163     </file>
25164   </example>
25165  */
25166 var ngHideDirective = ['$animate', function($animate) {
25167   return {
25168     restrict: 'A',
25169     multiElement: true,
25170     link: function(scope, element, attr) {
25171       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
25172         // The comment inside of the ngShowDirective explains why we add and
25173         // remove a temporary class for the show/hide animation
25174         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
25175           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
25176         });
25177       });
25178     }
25179   };
25180 }];
25181
25182 /**
25183  * @ngdoc directive
25184  * @name ngStyle
25185  * @restrict AC
25186  *
25187  * @description
25188  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
25189  *
25190  * @element ANY
25191  * @param {expression} ngStyle
25192  *
25193  * {@link guide/expression Expression} which evals to an
25194  * object whose keys are CSS style names and values are corresponding values for those CSS
25195  * keys.
25196  *
25197  * Since some CSS style names are not valid keys for an object, they must be quoted.
25198  * See the 'background-color' style in the example below.
25199  *
25200  * @example
25201    <example>
25202      <file name="index.html">
25203         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
25204         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
25205         <input type="button" value="clear" ng-click="myStyle={}">
25206         <br/>
25207         <span ng-style="myStyle">Sample Text</span>
25208         <pre>myStyle={{myStyle}}</pre>
25209      </file>
25210      <file name="style.css">
25211        span {
25212          color: black;
25213        }
25214      </file>
25215      <file name="protractor.js" type="protractor">
25216        var colorSpan = element(by.css('span'));
25217
25218        it('should check ng-style', function() {
25219          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
25220          element(by.css('input[value=\'set color\']')).click();
25221          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
25222          element(by.css('input[value=clear]')).click();
25223          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
25224        });
25225      </file>
25226    </example>
25227  */
25228 var ngStyleDirective = ngDirective(function(scope, element, attr) {
25229   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
25230     if (oldStyles && (newStyles !== oldStyles)) {
25231       forEach(oldStyles, function(val, style) { element.css(style, '');});
25232     }
25233     if (newStyles) element.css(newStyles);
25234   }, true);
25235 });
25236
25237 /**
25238  * @ngdoc directive
25239  * @name ngSwitch
25240  * @restrict EA
25241  *
25242  * @description
25243  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
25244  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
25245  * as specified in the template.
25246  *
25247  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
25248  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
25249  * matches the value obtained from the evaluated expression. In other words, you define a container element
25250  * (where you place the directive), place an expression on the **`on="..."` attribute**
25251  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
25252  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
25253  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
25254  * attribute is displayed.
25255  *
25256  * <div class="alert alert-info">
25257  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
25258  * as literal string values to match against.
25259  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
25260  * value of the expression `$scope.someVal`.
25261  * </div>
25262
25263  * @animations
25264  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
25265  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
25266  *
25267  * @usage
25268  *
25269  * ```
25270  * <ANY ng-switch="expression">
25271  *   <ANY ng-switch-when="matchValue1">...</ANY>
25272  *   <ANY ng-switch-when="matchValue2">...</ANY>
25273  *   <ANY ng-switch-default>...</ANY>
25274  * </ANY>
25275  * ```
25276  *
25277  *
25278  * @scope
25279  * @priority 1200
25280  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
25281  * On child elements add:
25282  *
25283  * * `ngSwitchWhen`: the case statement to match against. If match then this
25284  *   case will be displayed. If the same match appears multiple times, all the
25285  *   elements will be displayed.
25286  * * `ngSwitchDefault`: the default case when no other case match. If there
25287  *   are multiple default cases, all of them will be displayed when no other
25288  *   case match.
25289  *
25290  *
25291  * @example
25292   <example module="switchExample" deps="angular-animate.js" animations="true">
25293     <file name="index.html">
25294       <div ng-controller="ExampleController">
25295         <select ng-model="selection" ng-options="item for item in items">
25296         </select>
25297         <code>selection={{selection}}</code>
25298         <hr/>
25299         <div class="animate-switch-container"
25300           ng-switch on="selection">
25301             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
25302             <div class="animate-switch" ng-switch-when="home">Home Span</div>
25303             <div class="animate-switch" ng-switch-default>default</div>
25304         </div>
25305       </div>
25306     </file>
25307     <file name="script.js">
25308       angular.module('switchExample', ['ngAnimate'])
25309         .controller('ExampleController', ['$scope', function($scope) {
25310           $scope.items = ['settings', 'home', 'other'];
25311           $scope.selection = $scope.items[0];
25312         }]);
25313     </file>
25314     <file name="animations.css">
25315       .animate-switch-container {
25316         position:relative;
25317         background:white;
25318         border:1px solid black;
25319         height:40px;
25320         overflow:hidden;
25321       }
25322
25323       .animate-switch {
25324         padding:10px;
25325       }
25326
25327       .animate-switch.ng-animate {
25328         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25329         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25330
25331         position:absolute;
25332         top:0;
25333         left:0;
25334         right:0;
25335         bottom:0;
25336       }
25337
25338       .animate-switch.ng-leave.ng-leave-active,
25339       .animate-switch.ng-enter {
25340         top:-50px;
25341       }
25342       .animate-switch.ng-leave,
25343       .animate-switch.ng-enter.ng-enter-active {
25344         top:0;
25345       }
25346     </file>
25347     <file name="protractor.js" type="protractor">
25348       var switchElem = element(by.css('[ng-switch]'));
25349       var select = element(by.model('selection'));
25350
25351       it('should start in settings', function() {
25352         expect(switchElem.getText()).toMatch(/Settings Div/);
25353       });
25354       it('should change to home', function() {
25355         select.all(by.css('option')).get(1).click();
25356         expect(switchElem.getText()).toMatch(/Home Span/);
25357       });
25358       it('should select default', function() {
25359         select.all(by.css('option')).get(2).click();
25360         expect(switchElem.getText()).toMatch(/default/);
25361       });
25362     </file>
25363   </example>
25364  */
25365 var ngSwitchDirective = ['$animate', function($animate) {
25366   return {
25367     restrict: 'EA',
25368     require: 'ngSwitch',
25369
25370     // asks for $scope to fool the BC controller module
25371     controller: ['$scope', function ngSwitchController() {
25372      this.cases = {};
25373     }],
25374     link: function(scope, element, attr, ngSwitchController) {
25375       var watchExpr = attr.ngSwitch || attr.on,
25376           selectedTranscludes = [],
25377           selectedElements = [],
25378           previousLeaveAnimations = [],
25379           selectedScopes = [];
25380
25381       var spliceFactory = function(array, index) {
25382           return function() { array.splice(index, 1); };
25383       };
25384
25385       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
25386         var i, ii;
25387         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
25388           $animate.cancel(previousLeaveAnimations[i]);
25389         }
25390         previousLeaveAnimations.length = 0;
25391
25392         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
25393           var selected = getBlockNodes(selectedElements[i].clone);
25394           selectedScopes[i].$destroy();
25395           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
25396           promise.then(spliceFactory(previousLeaveAnimations, i));
25397         }
25398
25399         selectedElements.length = 0;
25400         selectedScopes.length = 0;
25401
25402         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
25403           forEach(selectedTranscludes, function(selectedTransclude) {
25404             selectedTransclude.transclude(function(caseElement, selectedScope) {
25405               selectedScopes.push(selectedScope);
25406               var anchor = selectedTransclude.element;
25407               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
25408               var block = { clone: caseElement };
25409
25410               selectedElements.push(block);
25411               $animate.enter(caseElement, anchor.parent(), anchor);
25412             });
25413           });
25414         }
25415       });
25416     }
25417   };
25418 }];
25419
25420 var ngSwitchWhenDirective = ngDirective({
25421   transclude: 'element',
25422   priority: 1200,
25423   require: '^ngSwitch',
25424   multiElement: true,
25425   link: function(scope, element, attrs, ctrl, $transclude) {
25426     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
25427     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
25428   }
25429 });
25430
25431 var ngSwitchDefaultDirective = ngDirective({
25432   transclude: 'element',
25433   priority: 1200,
25434   require: '^ngSwitch',
25435   multiElement: true,
25436   link: function(scope, element, attr, ctrl, $transclude) {
25437     ctrl.cases['?'] = (ctrl.cases['?'] || []);
25438     ctrl.cases['?'].push({ transclude: $transclude, element: element });
25439    }
25440 });
25441
25442 /**
25443  * @ngdoc directive
25444  * @name ngTransclude
25445  * @restrict EAC
25446  *
25447  * @description
25448  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
25449  *
25450  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
25451  *
25452  * @element ANY
25453  *
25454  * @example
25455    <example module="transcludeExample">
25456      <file name="index.html">
25457        <script>
25458          angular.module('transcludeExample', [])
25459           .directive('pane', function(){
25460              return {
25461                restrict: 'E',
25462                transclude: true,
25463                scope: { title:'@' },
25464                template: '<div style="border: 1px solid black;">' +
25465                            '<div style="background-color: gray">{{title}}</div>' +
25466                            '<ng-transclude></ng-transclude>' +
25467                          '</div>'
25468              };
25469          })
25470          .controller('ExampleController', ['$scope', function($scope) {
25471            $scope.title = 'Lorem Ipsum';
25472            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
25473          }]);
25474        </script>
25475        <div ng-controller="ExampleController">
25476          <input ng-model="title"> <br/>
25477          <textarea ng-model="text"></textarea> <br/>
25478          <pane title="{{title}}">{{text}}</pane>
25479        </div>
25480      </file>
25481      <file name="protractor.js" type="protractor">
25482         it('should have transcluded', function() {
25483           var titleElement = element(by.model('title'));
25484           titleElement.clear();
25485           titleElement.sendKeys('TITLE');
25486           var textElement = element(by.model('text'));
25487           textElement.clear();
25488           textElement.sendKeys('TEXT');
25489           expect(element(by.binding('title')).getText()).toEqual('TITLE');
25490           expect(element(by.binding('text')).getText()).toEqual('TEXT');
25491         });
25492      </file>
25493    </example>
25494  *
25495  */
25496 var ngTranscludeDirective = ngDirective({
25497   restrict: 'EAC',
25498   link: function($scope, $element, $attrs, controller, $transclude) {
25499     if (!$transclude) {
25500       throw minErr('ngTransclude')('orphan',
25501        'Illegal use of ngTransclude directive in the template! ' +
25502        'No parent directive that requires a transclusion found. ' +
25503        'Element: {0}',
25504        startingTag($element));
25505     }
25506
25507     $transclude(function(clone) {
25508       $element.empty();
25509       $element.append(clone);
25510     });
25511   }
25512 });
25513
25514 /**
25515  * @ngdoc directive
25516  * @name script
25517  * @restrict E
25518  *
25519  * @description
25520  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
25521  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
25522  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
25523  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
25524  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
25525  *
25526  * @param {string} type Must be set to `'text/ng-template'`.
25527  * @param {string} id Cache name of the template.
25528  *
25529  * @example
25530   <example>
25531     <file name="index.html">
25532       <script type="text/ng-template" id="/tpl.html">
25533         Content of the template.
25534       </script>
25535
25536       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
25537       <div id="tpl-content" ng-include src="currentTpl"></div>
25538     </file>
25539     <file name="protractor.js" type="protractor">
25540       it('should load template defined inside script tag', function() {
25541         element(by.css('#tpl-link')).click();
25542         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
25543       });
25544     </file>
25545   </example>
25546  */
25547 var scriptDirective = ['$templateCache', function($templateCache) {
25548   return {
25549     restrict: 'E',
25550     terminal: true,
25551     compile: function(element, attr) {
25552       if (attr.type == 'text/ng-template') {
25553         var templateUrl = attr.id,
25554             text = element[0].text;
25555
25556         $templateCache.put(templateUrl, text);
25557       }
25558     }
25559   };
25560 }];
25561
25562 var ngOptionsMinErr = minErr('ngOptions');
25563 /**
25564  * @ngdoc directive
25565  * @name select
25566  * @restrict E
25567  *
25568  * @description
25569  * HTML `SELECT` element with angular data-binding.
25570  *
25571  * # `ngOptions`
25572  *
25573  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
25574  * elements for the `<select>` element using the array or object obtained by evaluating the
25575  * `ngOptions` comprehension expression.
25576  *
25577  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
25578  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
25579  * increasing speed by not creating a new scope for each repeated instance, as well as providing
25580  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
25581  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
25582  *  to a non-string value. This is because an option element can only be bound to string values at
25583  * present.
25584  *
25585  * When an item in the `<select>` menu is selected, the array element or object property
25586  * represented by the selected option will be bound to the model identified by the `ngModel`
25587  * directive.
25588  *
25589  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
25590  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
25591  * option. See example below for demonstration.
25592  *
25593  * <div class="alert alert-warning">
25594  * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
25595  * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
25596  * </div>
25597  *
25598  * ## `select` **`as`**
25599  *
25600  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
25601  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
25602  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
25603  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
25604  *
25605  *
25606  * ### `select` **`as`** and **`track by`**
25607  *
25608  * <div class="alert alert-warning">
25609  * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
25610  * </div>
25611  *
25612  * Consider the following example:
25613  *
25614  * ```html
25615  * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
25616  * ```
25617  *
25618  * ```js
25619  * $scope.values = [{
25620  *   id: 1,
25621  *   label: 'aLabel',
25622  *   subItem: { name: 'aSubItem' }
25623  * }, {
25624  *   id: 2,
25625  *   label: 'bLabel',
25626  *   subItem: { name: 'bSubItem' }
25627  * }];
25628  *
25629  * $scope.selected = { name: 'aSubItem' };
25630  * ```
25631  *
25632  * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
25633  * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
25634  * following:
25635  *
25636  * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
25637  * 2. Apply **`track by`** to the already selected value in `ngModel`.
25638  *    In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
25639  *    value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
25640  *    a wrong object, the selected element can't be found, `<select>` is always reset to the "not
25641  *    selected" option.
25642  *
25643  *
25644  * @param {string} ngModel Assignable angular expression to data-bind to.
25645  * @param {string=} name Property name of the form under which the control is published.
25646  * @param {string=} required The control is considered valid only if value is entered.
25647  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25648  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25649  *    `required` when you want to data-bind to the `required` attribute.
25650  * @param {comprehension_expression=} ngOptions in one of the following forms:
25651  *
25652  *   * for array data sources:
25653  *     * `label` **`for`** `value` **`in`** `array`
25654  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
25655  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25656  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25657  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
25658  *        (for including a filter with `track by`)
25659  *   * for object data sources:
25660  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25661  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25662  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
25663  *     * `select` **`as`** `label` **`group by`** `group`
25664  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
25665  *
25666  * Where:
25667  *
25668  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
25669  *   * `value`: local variable which will refer to each item in the `array` or each property value
25670  *      of `object` during iteration.
25671  *   * `key`: local variable which will refer to a property name in `object` during iteration.
25672  *   * `label`: The result of this expression will be the label for `<option>` element. The
25673  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
25674  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
25675  *      element. If not specified, `select` expression will default to `value`.
25676  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
25677  *      DOM element.
25678  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
25679  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
25680  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
25681  *      even when the options are recreated (e.g. reloaded from the server).
25682  *
25683  * @example
25684     <example module="selectExample">
25685       <file name="index.html">
25686         <script>
25687         angular.module('selectExample', [])
25688           .controller('ExampleController', ['$scope', function($scope) {
25689             $scope.colors = [
25690               {name:'black', shade:'dark'},
25691               {name:'white', shade:'light'},
25692               {name:'red', shade:'dark'},
25693               {name:'blue', shade:'dark'},
25694               {name:'yellow', shade:'light'}
25695             ];
25696             $scope.myColor = $scope.colors[2]; // red
25697           }]);
25698         </script>
25699         <div ng-controller="ExampleController">
25700           <ul>
25701             <li ng-repeat="color in colors">
25702               Name: <input ng-model="color.name">
25703               [<a href ng-click="colors.splice($index, 1)">X</a>]
25704             </li>
25705             <li>
25706               [<a href ng-click="colors.push({})">add</a>]
25707             </li>
25708           </ul>
25709           <hr/>
25710           Color (null not allowed):
25711           <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
25712
25713           Color (null allowed):
25714           <span  class="nullable">
25715             <select ng-model="myColor" ng-options="color.name for color in colors">
25716               <option value="">-- choose color --</option>
25717             </select>
25718           </span><br/>
25719
25720           Color grouped by shade:
25721           <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
25722           </select><br/>
25723
25724
25725           Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
25726           <hr/>
25727           Currently selected: {{ {selected_color:myColor} }}
25728           <div style="border:solid 1px black; height:20px"
25729                ng-style="{'background-color':myColor.name}">
25730           </div>
25731         </div>
25732       </file>
25733       <file name="protractor.js" type="protractor">
25734          it('should check ng-options', function() {
25735            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
25736            element.all(by.model('myColor')).first().click();
25737            element.all(by.css('select[ng-model="myColor"] option')).first().click();
25738            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
25739            element(by.css('.nullable select[ng-model="myColor"]')).click();
25740            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
25741            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
25742          });
25743       </file>
25744     </example>
25745  */
25746
25747 var ngOptionsDirective = valueFn({
25748   restrict: 'A',
25749   terminal: true
25750 });
25751
25752 // jshint maxlen: false
25753 var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
25754                          //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
25755   var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
25756       nullModelCtrl = {$setViewValue: noop};
25757 // jshint maxlen: 100
25758
25759   return {
25760     restrict: 'E',
25761     require: ['select', '?ngModel'],
25762     controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
25763       var self = this,
25764           optionsMap = {},
25765           ngModelCtrl = nullModelCtrl,
25766           nullOption,
25767           unknownOption;
25768
25769
25770       self.databound = $attrs.ngModel;
25771
25772
25773       self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
25774         ngModelCtrl = ngModelCtrl_;
25775         nullOption = nullOption_;
25776         unknownOption = unknownOption_;
25777       };
25778
25779
25780       self.addOption = function(value, element) {
25781         assertNotHasOwnProperty(value, '"option value"');
25782         optionsMap[value] = true;
25783
25784         if (ngModelCtrl.$viewValue == value) {
25785           $element.val(value);
25786           if (unknownOption.parent()) unknownOption.remove();
25787         }
25788         // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
25789         // Adding an <option selected="selected"> element to a <select required="required"> should
25790         // automatically select the new element
25791         if (element && element[0].hasAttribute('selected')) {
25792           element[0].selected = true;
25793         }
25794       };
25795
25796
25797       self.removeOption = function(value) {
25798         if (this.hasOption(value)) {
25799           delete optionsMap[value];
25800           if (ngModelCtrl.$viewValue === value) {
25801             this.renderUnknownOption(value);
25802           }
25803         }
25804       };
25805
25806
25807       self.renderUnknownOption = function(val) {
25808         var unknownVal = '? ' + hashKey(val) + ' ?';
25809         unknownOption.val(unknownVal);
25810         $element.prepend(unknownOption);
25811         $element.val(unknownVal);
25812         unknownOption.prop('selected', true); // needed for IE
25813       };
25814
25815
25816       self.hasOption = function(value) {
25817         return optionsMap.hasOwnProperty(value);
25818       };
25819
25820       $scope.$on('$destroy', function() {
25821         // disable unknown option so that we don't do work when the whole select is being destroyed
25822         self.renderUnknownOption = noop;
25823       });
25824     }],
25825
25826     link: function(scope, element, attr, ctrls) {
25827       // if ngModel is not defined, we don't need to do anything
25828       if (!ctrls[1]) return;
25829
25830       var selectCtrl = ctrls[0],
25831           ngModelCtrl = ctrls[1],
25832           multiple = attr.multiple,
25833           optionsExp = attr.ngOptions,
25834           nullOption = false, // if false, user will not be able to select it (used by ngOptions)
25835           emptyOption,
25836           renderScheduled = false,
25837           // we can't just jqLite('<option>') since jqLite is not smart enough
25838           // to create it in <select> and IE barfs otherwise.
25839           optionTemplate = jqLite(document.createElement('option')),
25840           optGroupTemplate =jqLite(document.createElement('optgroup')),
25841           unknownOption = optionTemplate.clone();
25842
25843       // find "null" option
25844       for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
25845         if (children[i].value === '') {
25846           emptyOption = nullOption = children.eq(i);
25847           break;
25848         }
25849       }
25850
25851       selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
25852
25853       // required validator
25854       if (multiple) {
25855         ngModelCtrl.$isEmpty = function(value) {
25856           return !value || value.length === 0;
25857         };
25858       }
25859
25860       if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
25861       else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
25862       else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
25863
25864
25865       ////////////////////////////
25866
25867
25868
25869       function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
25870         ngModelCtrl.$render = function() {
25871           var viewValue = ngModelCtrl.$viewValue;
25872
25873           if (selectCtrl.hasOption(viewValue)) {
25874             if (unknownOption.parent()) unknownOption.remove();
25875             selectElement.val(viewValue);
25876             if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
25877           } else {
25878             if (viewValue == null && emptyOption) {
25879               selectElement.val('');
25880             } else {
25881               selectCtrl.renderUnknownOption(viewValue);
25882             }
25883           }
25884         };
25885
25886         selectElement.on('change', function() {
25887           scope.$apply(function() {
25888             if (unknownOption.parent()) unknownOption.remove();
25889             ngModelCtrl.$setViewValue(selectElement.val());
25890           });
25891         });
25892       }
25893
25894       function setupAsMultiple(scope, selectElement, ctrl) {
25895         var lastView;
25896         ctrl.$render = function() {
25897           var items = new HashMap(ctrl.$viewValue);
25898           forEach(selectElement.find('option'), function(option) {
25899             option.selected = isDefined(items.get(option.value));
25900           });
25901         };
25902
25903         // we have to do it on each watch since ngModel watches reference, but
25904         // we need to work of an array, so we need to see if anything was inserted/removed
25905         scope.$watch(function selectMultipleWatch() {
25906           if (!equals(lastView, ctrl.$viewValue)) {
25907             lastView = shallowCopy(ctrl.$viewValue);
25908             ctrl.$render();
25909           }
25910         });
25911
25912         selectElement.on('change', function() {
25913           scope.$apply(function() {
25914             var array = [];
25915             forEach(selectElement.find('option'), function(option) {
25916               if (option.selected) {
25917                 array.push(option.value);
25918               }
25919             });
25920             ctrl.$setViewValue(array);
25921           });
25922         });
25923       }
25924
25925       function setupAsOptions(scope, selectElement, ctrl) {
25926         var match;
25927
25928         if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
25929           throw ngOptionsMinErr('iexp',
25930             "Expected expression in form of " +
25931             "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
25932             " but got '{0}'. Element: {1}",
25933             optionsExp, startingTag(selectElement));
25934         }
25935
25936         var displayFn = $parse(match[2] || match[1]),
25937             valueName = match[4] || match[6],
25938             selectAs = / as /.test(match[0]) && match[1],
25939             selectAsFn = selectAs ? $parse(selectAs) : null,
25940             keyName = match[5],
25941             groupByFn = $parse(match[3] || ''),
25942             valueFn = $parse(match[2] ? match[1] : valueName),
25943             valuesFn = $parse(match[7]),
25944             track = match[8],
25945             trackFn = track ? $parse(match[8]) : null,
25946             trackKeysCache = {},
25947             // This is an array of array of existing option groups in DOM.
25948             // We try to reuse these if possible
25949             // - optionGroupsCache[0] is the options with no option group
25950             // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
25951             optionGroupsCache = [[{element: selectElement, label:''}]],
25952             //re-usable object to represent option's locals
25953             locals = {};
25954
25955         if (nullOption) {
25956           // compile the element since there might be bindings in it
25957           $compile(nullOption)(scope);
25958
25959           // remove the class, which is added automatically because we recompile the element and it
25960           // becomes the compilation root
25961           nullOption.removeClass('ng-scope');
25962
25963           // we need to remove it before calling selectElement.empty() because otherwise IE will
25964           // remove the label from the element. wtf?
25965           nullOption.remove();
25966         }
25967
25968         // clear contents, we'll add what's needed based on the model
25969         selectElement.empty();
25970
25971         selectElement.on('change', selectionChanged);
25972
25973         ctrl.$render = render;
25974
25975         scope.$watchCollection(valuesFn, scheduleRendering);
25976         scope.$watchCollection(getLabels, scheduleRendering);
25977
25978         if (multiple) {
25979           scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
25980         }
25981
25982         // ------------------------------------------------------------------ //
25983
25984         function callExpression(exprFn, key, value) {
25985           locals[valueName] = value;
25986           if (keyName) locals[keyName] = key;
25987           return exprFn(scope, locals);
25988         }
25989
25990         function selectionChanged() {
25991           scope.$apply(function() {
25992             var collection = valuesFn(scope) || [];
25993             var viewValue;
25994             if (multiple) {
25995               viewValue = [];
25996               forEach(selectElement.val(), function(selectedKey) {
25997                   selectedKey = trackFn ? trackKeysCache[selectedKey] : selectedKey;
25998                 viewValue.push(getViewValue(selectedKey, collection[selectedKey]));
25999               });
26000             } else {
26001               var selectedKey = trackFn ? trackKeysCache[selectElement.val()] : selectElement.val();
26002               viewValue = getViewValue(selectedKey, collection[selectedKey]);
26003             }
26004             ctrl.$setViewValue(viewValue);
26005             render();
26006           });
26007         }
26008
26009         function getViewValue(key, value) {
26010           if (key === '?') {
26011             return undefined;
26012           } else if (key === '') {
26013             return null;
26014           } else {
26015             var viewValueFn = selectAsFn ? selectAsFn : valueFn;
26016             return callExpression(viewValueFn, key, value);
26017           }
26018         }
26019
26020         function getLabels() {
26021           var values = valuesFn(scope);
26022           var toDisplay;
26023           if (values && isArray(values)) {
26024             toDisplay = new Array(values.length);
26025             for (var i = 0, ii = values.length; i < ii; i++) {
26026               toDisplay[i] = callExpression(displayFn, i, values[i]);
26027             }
26028             return toDisplay;
26029           } else if (values) {
26030             // TODO: Add a test for this case
26031             toDisplay = {};
26032             for (var prop in values) {
26033               if (values.hasOwnProperty(prop)) {
26034                 toDisplay[prop] = callExpression(displayFn, prop, values[prop]);
26035               }
26036             }
26037           }
26038           return toDisplay;
26039         }
26040
26041         function createIsSelectedFn(viewValue) {
26042           var selectedSet;
26043           if (multiple) {
26044             if (trackFn && isArray(viewValue)) {
26045
26046               selectedSet = new HashMap([]);
26047               for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
26048                 // tracking by key
26049                 selectedSet.put(callExpression(trackFn, null, viewValue[trackIndex]), true);
26050               }
26051             } else {
26052               selectedSet = new HashMap(viewValue);
26053             }
26054           } else if (trackFn) {
26055             viewValue = callExpression(trackFn, null, viewValue);
26056           }
26057
26058           return function isSelected(key, value) {
26059             var compareValueFn;
26060             if (trackFn) {
26061               compareValueFn = trackFn;
26062             } else if (selectAsFn) {
26063               compareValueFn = selectAsFn;
26064             } else {
26065               compareValueFn = valueFn;
26066             }
26067
26068             if (multiple) {
26069               return isDefined(selectedSet.remove(callExpression(compareValueFn, key, value)));
26070             } else {
26071               return viewValue === callExpression(compareValueFn, key, value);
26072             }
26073           };
26074         }
26075
26076         function scheduleRendering() {
26077           if (!renderScheduled) {
26078             scope.$$postDigest(render);
26079             renderScheduled = true;
26080           }
26081         }
26082
26083         /**
26084          * A new labelMap is created with each render.
26085          * This function is called for each existing option with added=false,
26086          * and each new option with added=true.
26087          * - Labels that are passed to this method twice,
26088          * (once with added=true and once with added=false) will end up with a value of 0, and
26089          * will cause no change to happen to the corresponding option.
26090          * - Labels that are passed to this method only once with added=false will end up with a
26091          * value of -1 and will eventually be passed to selectCtrl.removeOption()
26092          * - Labels that are passed to this method only once with added=true will end up with a
26093          * value of 1 and will eventually be passed to selectCtrl.addOption()
26094         */
26095         function updateLabelMap(labelMap, label, added) {
26096           labelMap[label] = labelMap[label] || 0;
26097           labelMap[label] += (added ? 1 : -1);
26098         }
26099
26100         function render() {
26101           renderScheduled = false;
26102
26103           // Temporary location for the option groups before we render them
26104           var optionGroups = {'':[]},
26105               optionGroupNames = [''],
26106               optionGroupName,
26107               optionGroup,
26108               option,
26109               existingParent, existingOptions, existingOption,
26110               viewValue = ctrl.$viewValue,
26111               values = valuesFn(scope) || [],
26112               keys = keyName ? sortedKeys(values) : values,
26113               key,
26114               value,
26115               groupLength, length,
26116               groupIndex, index,
26117               labelMap = {},
26118               selected,
26119               isSelected = createIsSelectedFn(viewValue),
26120               anySelected = false,
26121               lastElement,
26122               element,
26123               label,
26124               optionId;
26125
26126           trackKeysCache = {};
26127
26128           // We now build up the list of options we need (we merge later)
26129           for (index = 0; length = keys.length, index < length; index++) {
26130             key = index;
26131             if (keyName) {
26132               key = keys[index];
26133               if (key.charAt(0) === '$') continue;
26134             }
26135             value = values[key];
26136
26137             optionGroupName = callExpression(groupByFn, key, value) || '';
26138             if (!(optionGroup = optionGroups[optionGroupName])) {
26139               optionGroup = optionGroups[optionGroupName] = [];
26140               optionGroupNames.push(optionGroupName);
26141             }
26142
26143             selected = isSelected(key, value);
26144             anySelected = anySelected || selected;
26145
26146             label = callExpression(displayFn, key, value); // what will be seen by the user
26147
26148             // doing displayFn(scope, locals) || '' overwrites zero values
26149             label = isDefined(label) ? label : '';
26150             optionId = trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index);
26151             if (trackFn) {
26152               trackKeysCache[optionId] = key;
26153             }
26154
26155             optionGroup.push({
26156               // either the index into array or key from object
26157               id: optionId,
26158               label: label,
26159               selected: selected                   // determine if we should be selected
26160             });
26161           }
26162           if (!multiple) {
26163             if (nullOption || viewValue === null) {
26164               // insert null option if we have a placeholder, or the model is null
26165               optionGroups[''].unshift({id:'', label:'', selected:!anySelected});
26166             } else if (!anySelected) {
26167               // option could not be found, we have to insert the undefined item
26168               optionGroups[''].unshift({id:'?', label:'', selected:true});
26169             }
26170           }
26171
26172           // Now we need to update the list of DOM nodes to match the optionGroups we computed above
26173           for (groupIndex = 0, groupLength = optionGroupNames.length;
26174                groupIndex < groupLength;
26175                groupIndex++) {
26176             // current option group name or '' if no group
26177             optionGroupName = optionGroupNames[groupIndex];
26178
26179             // list of options for that group. (first item has the parent)
26180             optionGroup = optionGroups[optionGroupName];
26181
26182             if (optionGroupsCache.length <= groupIndex) {
26183               // we need to grow the optionGroups
26184               existingParent = {
26185                 element: optGroupTemplate.clone().attr('label', optionGroupName),
26186                 label: optionGroup.label
26187               };
26188               existingOptions = [existingParent];
26189               optionGroupsCache.push(existingOptions);
26190               selectElement.append(existingParent.element);
26191             } else {
26192               existingOptions = optionGroupsCache[groupIndex];
26193               existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
26194
26195               // update the OPTGROUP label if not the same.
26196               if (existingParent.label != optionGroupName) {
26197                 existingParent.element.attr('label', existingParent.label = optionGroupName);
26198               }
26199             }
26200
26201             lastElement = null;  // start at the beginning
26202             for (index = 0, length = optionGroup.length; index < length; index++) {
26203               option = optionGroup[index];
26204               if ((existingOption = existingOptions[index + 1])) {
26205                 // reuse elements
26206                 lastElement = existingOption.element;
26207                 if (existingOption.label !== option.label) {
26208                   updateLabelMap(labelMap, existingOption.label, false);
26209                   updateLabelMap(labelMap, option.label, true);
26210                   lastElement.text(existingOption.label = option.label);
26211                   lastElement.prop('label', existingOption.label);
26212                 }
26213                 if (existingOption.id !== option.id) {
26214                   lastElement.val(existingOption.id = option.id);
26215                 }
26216                 // lastElement.prop('selected') provided by jQuery has side-effects
26217                 if (lastElement[0].selected !== option.selected) {
26218                   lastElement.prop('selected', (existingOption.selected = option.selected));
26219                   if (msie) {
26220                     // See #7692
26221                     // The selected item wouldn't visually update on IE without this.
26222                     // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
26223                     lastElement.prop('selected', existingOption.selected);
26224                   }
26225                 }
26226               } else {
26227                 // grow elements
26228
26229                 // if it's a null option
26230                 if (option.id === '' && nullOption) {
26231                   // put back the pre-compiled element
26232                   element = nullOption;
26233                 } else {
26234                   // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
26235                   // in this version of jQuery on some browser the .text() returns a string
26236                   // rather then the element.
26237                   (element = optionTemplate.clone())
26238                       .val(option.id)
26239                       .prop('selected', option.selected)
26240                       .attr('selected', option.selected)
26241                       .prop('label', option.label)
26242                       .text(option.label);
26243                 }
26244
26245                 existingOptions.push(existingOption = {
26246                     element: element,
26247                     label: option.label,
26248                     id: option.id,
26249                     selected: option.selected
26250                 });
26251                 updateLabelMap(labelMap, option.label, true);
26252                 if (lastElement) {
26253                   lastElement.after(element);
26254                 } else {
26255                   existingParent.element.append(element);
26256                 }
26257                 lastElement = element;
26258               }
26259             }
26260             // remove any excessive OPTIONs in a group
26261             index++; // increment since the existingOptions[0] is parent element not OPTION
26262             while (existingOptions.length > index) {
26263               option = existingOptions.pop();
26264               updateLabelMap(labelMap, option.label, false);
26265               option.element.remove();
26266             }
26267           }
26268           // remove any excessive OPTGROUPs from select
26269           while (optionGroupsCache.length > groupIndex) {
26270             // remove all the labels in the option group
26271             optionGroup = optionGroupsCache.pop();
26272             for (index = 1; index < optionGroup.length; ++index) {
26273               updateLabelMap(labelMap, optionGroup[index].label, false);
26274             }
26275             optionGroup[0].element.remove();
26276           }
26277           forEach(labelMap, function(count, label) {
26278             if (count > 0) {
26279               selectCtrl.addOption(label);
26280             } else if (count < 0) {
26281               selectCtrl.removeOption(label);
26282             }
26283           });
26284         }
26285       }
26286     }
26287   };
26288 }];
26289
26290 var optionDirective = ['$interpolate', function($interpolate) {
26291   var nullSelectCtrl = {
26292     addOption: noop,
26293     removeOption: noop
26294   };
26295
26296   return {
26297     restrict: 'E',
26298     priority: 100,
26299     compile: function(element, attr) {
26300       if (isUndefined(attr.value)) {
26301         var interpolateFn = $interpolate(element.text(), true);
26302         if (!interpolateFn) {
26303           attr.$set('value', element.text());
26304         }
26305       }
26306
26307       return function(scope, element, attr) {
26308         var selectCtrlName = '$selectController',
26309             parent = element.parent(),
26310             selectCtrl = parent.data(selectCtrlName) ||
26311               parent.parent().data(selectCtrlName); // in case we are in optgroup
26312
26313         if (!selectCtrl || !selectCtrl.databound) {
26314           selectCtrl = nullSelectCtrl;
26315         }
26316
26317         if (interpolateFn) {
26318           scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
26319             attr.$set('value', newVal);
26320             if (oldVal !== newVal) {
26321               selectCtrl.removeOption(oldVal);
26322             }
26323             selectCtrl.addOption(newVal, element);
26324           });
26325         } else {
26326           selectCtrl.addOption(attr.value, element);
26327         }
26328
26329         element.on('$destroy', function() {
26330           selectCtrl.removeOption(attr.value);
26331         });
26332       };
26333     }
26334   };
26335 }];
26336
26337 var styleDirective = valueFn({
26338   restrict: 'E',
26339   terminal: false
26340 });
26341
26342 var requiredDirective = function() {
26343   return {
26344     restrict: 'A',
26345     require: '?ngModel',
26346     link: function(scope, elm, attr, ctrl) {
26347       if (!ctrl) return;
26348       attr.required = true; // force truthy in case we are on non input element
26349
26350       ctrl.$validators.required = function(modelValue, viewValue) {
26351         return !attr.required || !ctrl.$isEmpty(viewValue);
26352       };
26353
26354       attr.$observe('required', function() {
26355         ctrl.$validate();
26356       });
26357     }
26358   };
26359 };
26360
26361
26362 var patternDirective = function() {
26363   return {
26364     restrict: 'A',
26365     require: '?ngModel',
26366     link: function(scope, elm, attr, ctrl) {
26367       if (!ctrl) return;
26368
26369       var regexp, patternExp = attr.ngPattern || attr.pattern;
26370       attr.$observe('pattern', function(regex) {
26371         if (isString(regex) && regex.length > 0) {
26372           regex = new RegExp('^' + regex + '$');
26373         }
26374
26375         if (regex && !regex.test) {
26376           throw minErr('ngPattern')('noregexp',
26377             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
26378             regex, startingTag(elm));
26379         }
26380
26381         regexp = regex || undefined;
26382         ctrl.$validate();
26383       });
26384
26385       ctrl.$validators.pattern = function(modelValue, viewValue) {
26386         // HTML5 pattern constraint validates the input value, so we validate the viewValue
26387         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
26388       };
26389     }
26390   };
26391 };
26392
26393
26394 var maxlengthDirective = function() {
26395   return {
26396     restrict: 'A',
26397     require: '?ngModel',
26398     link: function(scope, elm, attr, ctrl) {
26399       if (!ctrl) return;
26400
26401       var maxlength = -1;
26402       attr.$observe('maxlength', function(value) {
26403         var intVal = int(value);
26404         maxlength = isNaN(intVal) ? -1 : intVal;
26405         ctrl.$validate();
26406       });
26407       ctrl.$validators.maxlength = function(modelValue, viewValue) {
26408         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
26409       };
26410     }
26411   };
26412 };
26413
26414 var minlengthDirective = function() {
26415   return {
26416     restrict: 'A',
26417     require: '?ngModel',
26418     link: function(scope, elm, attr, ctrl) {
26419       if (!ctrl) return;
26420
26421       var minlength = 0;
26422       attr.$observe('minlength', function(value) {
26423         minlength = int(value) || 0;
26424         ctrl.$validate();
26425       });
26426       ctrl.$validators.minlength = function(modelValue, viewValue) {
26427         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
26428       };
26429     }
26430   };
26431 };
26432
26433   if (window.angular.bootstrap) {
26434     //AngularJS is already loaded, so we can return here...
26435     console.log('WARNING: Tried to load angular more than once.');
26436     return;
26437   }
26438
26439   //try to bind to jquery now so that one can write jqLite(document).ready()
26440   //but we will rebind on bootstrap again.
26441   bindJQuery();
26442
26443   publishExternalAPI(angular);
26444
26445   jqLite(document).ready(function() {
26446     angularInit(document, bootstrap);
26447   });
26448
26449 })(window, document);
26450
26451 !window.angular.$$csp() && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>');