Built motion from commit 7e022ab.|2.0.14
[motion2.git] / public / bower_components / angular / angular.js
1 /**
2  * @license AngularJS v1.5.10
3  * (c) 2010-2016 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window) {'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 SKIP_INDEXES = 2;
42
43     var templateArgs = arguments,
44       code = templateArgs[0],
45       message = '[' + (module ? module + ':' : '') + code + '] ',
46       template = templateArgs[1],
47       paramPrefix, i;
48
49     message += template.replace(/\{\d+\}/g, function(match) {
50       var index = +match.slice(1, -1),
51         shiftedIndex = index + SKIP_INDEXES;
52
53       if (shiftedIndex < templateArgs.length) {
54         return toDebugString(templateArgs[shiftedIndex]);
55       }
56
57       return match;
58     });
59
60     message += '\nhttp://errors.angularjs.org/1.5.10/' +
61       (module ? module + '/' : '') + code;
62
63     for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
64       message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
65         encodeURIComponent(toDebugString(templateArgs[i]));
66     }
67
68     return new ErrorConstructor(message);
69   };
70 }
71
72 /* We need to tell ESLint what variables are being exported */
73 /* exported
74   angular,
75   msie,
76   jqLite,
77   jQuery,
78   slice,
79   splice,
80   push,
81   toString,
82   ngMinErr,
83   angularModule,
84   uid,
85   REGEX_STRING_REGEXP,
86   VALIDITY_STATE_PROPERTY,
87
88   lowercase,
89   uppercase,
90   manualLowercase,
91   manualUppercase,
92   nodeName_,
93   isArrayLike,
94   forEach,
95   forEachSorted,
96   reverseParams,
97   nextUid,
98   setHashKey,
99   extend,
100   toInt,
101   inherit,
102   merge,
103   noop,
104   identity,
105   valueFn,
106   isUndefined,
107   isDefined,
108   isObject,
109   isBlankObject,
110   isString,
111   isNumber,
112   isNumberNaN,
113   isDate,
114   isArray,
115   isFunction,
116   isRegExp,
117   isWindow,
118   isScope,
119   isFile,
120   isFormData,
121   isBlob,
122   isBoolean,
123   isPromiseLike,
124   trim,
125   escapeForRegexp,
126   isElement,
127   makeMap,
128   includes,
129   arrayRemove,
130   copy,
131   equals,
132   csp,
133   jq,
134   concat,
135   sliceArgs,
136   bind,
137   toJsonReplacer,
138   toJson,
139   fromJson,
140   convertTimezoneToLocal,
141   timezoneToOffset,
142   startingTag,
143   tryDecodeURIComponent,
144   parseKeyValue,
145   toKeyValue,
146   encodeUriSegment,
147   encodeUriQuery,
148   angularInit,
149   bootstrap,
150   getTestability,
151   snake_case,
152   bindJQuery,
153   assertArg,
154   assertArgFn,
155   assertNotHasOwnProperty,
156   getter,
157   getBlockNodes,
158   hasOwnProperty,
159   createMap,
160
161   NODE_TYPE_ELEMENT,
162   NODE_TYPE_ATTRIBUTE,
163   NODE_TYPE_TEXT,
164   NODE_TYPE_COMMENT,
165   NODE_TYPE_DOCUMENT,
166   NODE_TYPE_DOCUMENT_FRAGMENT
167 */
168
169 ////////////////////////////////////
170
171 /**
172  * @ngdoc module
173  * @name ng
174  * @module ng
175  * @installation
176  * @description
177  *
178  * # ng (core module)
179  * The ng module is loaded by default when an AngularJS application is started. The module itself
180  * contains the essential components for an AngularJS application to function. The table below
181  * lists a high level breakdown of each of the services/factories, filters, directives and testing
182  * components available within this core module.
183  *
184  * <div doc-module-components="ng"></div>
185  */
186
187 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
188
189 // The name of a form control's ValidityState property.
190 // This is used so that it's possible for internal tests to create mock ValidityStates.
191 var VALIDITY_STATE_PROPERTY = 'validity';
192
193 var hasOwnProperty = Object.prototype.hasOwnProperty;
194
195 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
196 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
197
198
199 var manualLowercase = function(s) {
200   /* eslint-disable no-bitwise */
201   return isString(s)
202       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
203       : s;
204   /* eslint-enable */
205 };
206 var manualUppercase = function(s) {
207   /* eslint-disable no-bitwise */
208   return isString(s)
209       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
210       : s;
211   /* eslint-enable */
212 };
213
214
215 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
216 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
217 // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
218 if ('i' !== 'I'.toLowerCase()) {
219   lowercase = manualLowercase;
220   uppercase = manualUppercase;
221 }
222
223
224 var
225     msie,             // holds major version number for IE, or NaN if UA is not IE.
226     jqLite,           // delay binding since jQuery could be loaded after us.
227     jQuery,           // delay binding
228     slice             = [].slice,
229     splice            = [].splice,
230     push              = [].push,
231     toString          = Object.prototype.toString,
232     getPrototypeOf    = Object.getPrototypeOf,
233     ngMinErr          = minErr('ng'),
234
235     /** @name angular */
236     angular           = window.angular || (window.angular = {}),
237     angularModule,
238     uid               = 0;
239
240 /**
241  * documentMode is an IE-only property
242  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
243  */
244 msie = window.document.documentMode;
245
246
247 /**
248  * @private
249  * @param {*} obj
250  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
251  *                   String ...)
252  */
253 function isArrayLike(obj) {
254
255   // `null`, `undefined` and `window` are not array-like
256   if (obj == null || isWindow(obj)) return false;
257
258   // arrays, strings and jQuery/jqLite objects are array like
259   // * jqLite is either the jQuery or jqLite constructor function
260   // * we have to check the existence of jqLite first as this method is called
261   //   via the forEach method when constructing the jqLite object in the first place
262   if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
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   // NodeList objects (with `item` method) and
269   // other objects with suitable length characteristics are array-like
270   return isNumber(length) &&
271     (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item === 'function');
272
273 }
274
275 /**
276  * @ngdoc function
277  * @name angular.forEach
278  * @module ng
279  * @kind function
280  *
281  * @description
282  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
283  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
284  * is the value of an object property or an array element, `key` is the object property key or
285  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
286  *
287  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
288  * using the `hasOwnProperty` method.
289  *
290  * Unlike ES262's
291  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
292  * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
293  * return the value provided.
294  *
295    ```js
296      var values = {name: 'misko', gender: 'male'};
297      var log = [];
298      angular.forEach(values, function(value, key) {
299        this.push(key + ': ' + value);
300      }, log);
301      expect(log).toEqual(['name: misko', 'gender: male']);
302    ```
303  *
304  * @param {Object|Array} obj Object to iterate over.
305  * @param {Function} iterator Iterator function.
306  * @param {Object=} context Object to become context (`this`) for the iterator function.
307  * @returns {Object|Array} Reference to `obj`.
308  */
309
310 function forEach(obj, iterator, context) {
311   var key, length;
312   if (obj) {
313     if (isFunction(obj)) {
314       for (key in obj) {
315         // Need to check if hasOwnProperty exists,
316         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
317         if (key !== 'prototype' && key !== 'length' && key !== 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
318           iterator.call(context, obj[key], key, obj);
319         }
320       }
321     } else if (isArray(obj) || isArrayLike(obj)) {
322       var isPrimitive = typeof obj !== 'object';
323       for (key = 0, length = obj.length; key < length; key++) {
324         if (isPrimitive || key in obj) {
325           iterator.call(context, obj[key], key, obj);
326         }
327       }
328     } else if (obj.forEach && obj.forEach !== forEach) {
329         obj.forEach(iterator, context, obj);
330     } else if (isBlankObject(obj)) {
331       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
332       for (key in obj) {
333         iterator.call(context, obj[key], key, obj);
334       }
335     } else if (typeof obj.hasOwnProperty === 'function') {
336       // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
337       for (key in obj) {
338         if (obj.hasOwnProperty(key)) {
339           iterator.call(context, obj[key], key, obj);
340         }
341       }
342     } else {
343       // Slow path for objects which do not have a method `hasOwnProperty`
344       for (key in obj) {
345         if (hasOwnProperty.call(obj, key)) {
346           iterator.call(context, obj[key], key, obj);
347         }
348       }
349     }
350   }
351   return obj;
352 }
353
354 function forEachSorted(obj, iterator, context) {
355   var keys = Object.keys(obj).sort();
356   for (var i = 0; i < keys.length; i++) {
357     iterator.call(context, obj[keys[i]], keys[i]);
358   }
359   return keys;
360 }
361
362
363 /**
364  * when using forEach the params are value, key, but it is often useful to have key, value.
365  * @param {function(string, *)} iteratorFn
366  * @returns {function(*, string)}
367  */
368 function reverseParams(iteratorFn) {
369   return function(value, key) {iteratorFn(key, value);};
370 }
371
372 /**
373  * A consistent way of creating unique IDs in angular.
374  *
375  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
376  * we hit number precision issues in JavaScript.
377  *
378  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
379  *
380  * @returns {number} an unique alpha-numeric string
381  */
382 function nextUid() {
383   return ++uid;
384 }
385
386
387 /**
388  * Set or clear the hashkey for an object.
389  * @param obj object
390  * @param h the hashkey (!truthy to delete the hashkey)
391  */
392 function setHashKey(obj, h) {
393   if (h) {
394     obj.$$hashKey = h;
395   } else {
396     delete obj.$$hashKey;
397   }
398 }
399
400
401 function baseExtend(dst, objs, deep) {
402   var h = dst.$$hashKey;
403
404   for (var i = 0, ii = objs.length; i < ii; ++i) {
405     var obj = objs[i];
406     if (!isObject(obj) && !isFunction(obj)) continue;
407     var keys = Object.keys(obj);
408     for (var j = 0, jj = keys.length; j < jj; j++) {
409       var key = keys[j];
410       var src = obj[key];
411
412       if (deep && isObject(src)) {
413         if (isDate(src)) {
414           dst[key] = new Date(src.valueOf());
415         } else if (isRegExp(src)) {
416           dst[key] = new RegExp(src);
417         } else if (src.nodeName) {
418           dst[key] = src.cloneNode(true);
419         } else if (isElement(src)) {
420           dst[key] = src.clone();
421         } else {
422           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
423           baseExtend(dst[key], [src], true);
424         }
425       } else {
426         dst[key] = src;
427       }
428     }
429   }
430
431   setHashKey(dst, h);
432   return dst;
433 }
434
435 /**
436  * @ngdoc function
437  * @name angular.extend
438  * @module ng
439  * @kind function
440  *
441  * @description
442  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
443  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
444  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
445  *
446  * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
447  * {@link angular.merge} for this.
448  *
449  * @param {Object} dst Destination object.
450  * @param {...Object} src Source object(s).
451  * @returns {Object} Reference to `dst`.
452  */
453 function extend(dst) {
454   return baseExtend(dst, slice.call(arguments, 1), false);
455 }
456
457
458 /**
459 * @ngdoc function
460 * @name angular.merge
461 * @module ng
462 * @kind function
463 *
464 * @description
465 * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
466 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
467 * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
468 *
469 * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
470 * objects, performing a deep copy.
471 *
472 * @param {Object} dst Destination object.
473 * @param {...Object} src Source object(s).
474 * @returns {Object} Reference to `dst`.
475 */
476 function merge(dst) {
477   return baseExtend(dst, slice.call(arguments, 1), true);
478 }
479
480
481
482 function toInt(str) {
483   return parseInt(str, 10);
484 }
485
486 var isNumberNaN = Number.isNaN || function isNumberNaN(num) {
487   // eslint-disable-next-line no-self-compare
488   return num !== num;
489 };
490
491
492 function inherit(parent, extra) {
493   return extend(Object.create(parent), extra);
494 }
495
496 /**
497  * @ngdoc function
498  * @name angular.noop
499  * @module ng
500  * @kind function
501  *
502  * @description
503  * A function that performs no operations. This function can be useful when writing code in the
504  * functional style.
505    ```js
506      function foo(callback) {
507        var result = calculateResult();
508        (callback || angular.noop)(result);
509      }
510    ```
511  */
512 function noop() {}
513 noop.$inject = [];
514
515
516 /**
517  * @ngdoc function
518  * @name angular.identity
519  * @module ng
520  * @kind function
521  *
522  * @description
523  * A function that returns its first argument. This function is useful when writing code in the
524  * functional style.
525  *
526    ```js
527    function transformer(transformationFn, value) {
528      return (transformationFn || angular.identity)(value);
529    };
530
531    // E.g.
532    function getResult(fn, input) {
533      return (fn || angular.identity)(input);
534    };
535
536    getResult(function(n) { return n * 2; }, 21);   // returns 42
537    getResult(null, 21);                            // returns 21
538    getResult(undefined, 21);                       // returns 21
539    ```
540  *
541  * @param {*} value to be returned.
542  * @returns {*} the value passed in.
543  */
544 function identity($) {return $;}
545 identity.$inject = [];
546
547
548 function valueFn(value) {return function valueRef() {return value;};}
549
550 function hasCustomToString(obj) {
551   return isFunction(obj.toString) && obj.toString !== toString;
552 }
553
554
555 /**
556  * @ngdoc function
557  * @name angular.isUndefined
558  * @module ng
559  * @kind function
560  *
561  * @description
562  * Determines if a reference is undefined.
563  *
564  * @param {*} value Reference to check.
565  * @returns {boolean} True if `value` is undefined.
566  */
567 function isUndefined(value) {return typeof value === 'undefined';}
568
569
570 /**
571  * @ngdoc function
572  * @name angular.isDefined
573  * @module ng
574  * @kind function
575  *
576  * @description
577  * Determines if a reference is defined.
578  *
579  * @param {*} value Reference to check.
580  * @returns {boolean} True if `value` is defined.
581  */
582 function isDefined(value) {return typeof value !== 'undefined';}
583
584
585 /**
586  * @ngdoc function
587  * @name angular.isObject
588  * @module ng
589  * @kind function
590  *
591  * @description
592  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
593  * considered to be objects. Note that JavaScript arrays are objects.
594  *
595  * @param {*} value Reference to check.
596  * @returns {boolean} True if `value` is an `Object` but not `null`.
597  */
598 function isObject(value) {
599   // http://jsperf.com/isobject4
600   return value !== null && typeof value === 'object';
601 }
602
603
604 /**
605  * Determine if a value is an object with a null prototype
606  *
607  * @returns {boolean} True if `value` is an `Object` with a null prototype
608  */
609 function isBlankObject(value) {
610   return value !== null && typeof value === 'object' && !getPrototypeOf(value);
611 }
612
613
614 /**
615  * @ngdoc function
616  * @name angular.isString
617  * @module ng
618  * @kind function
619  *
620  * @description
621  * Determines if a reference is a `String`.
622  *
623  * @param {*} value Reference to check.
624  * @returns {boolean} True if `value` is a `String`.
625  */
626 function isString(value) {return typeof value === 'string';}
627
628
629 /**
630  * @ngdoc function
631  * @name angular.isNumber
632  * @module ng
633  * @kind function
634  *
635  * @description
636  * Determines if a reference is a `Number`.
637  *
638  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
639  *
640  * If you wish to exclude these then you can use the native
641  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
642  * method.
643  *
644  * @param {*} value Reference to check.
645  * @returns {boolean} True if `value` is a `Number`.
646  */
647 function isNumber(value) {return typeof value === 'number';}
648
649
650 /**
651  * @ngdoc function
652  * @name angular.isDate
653  * @module ng
654  * @kind function
655  *
656  * @description
657  * Determines if a value is a date.
658  *
659  * @param {*} value Reference to check.
660  * @returns {boolean} True if `value` is a `Date`.
661  */
662 function isDate(value) {
663   return toString.call(value) === '[object Date]';
664 }
665
666
667 /**
668  * @ngdoc function
669  * @name angular.isArray
670  * @module ng
671  * @kind function
672  *
673  * @description
674  * Determines if a reference is an `Array`. Alias of Array.isArray.
675  *
676  * @param {*} value Reference to check.
677  * @returns {boolean} True if `value` is an `Array`.
678  */
679 var isArray = Array.isArray;
680
681 /**
682  * @ngdoc function
683  * @name angular.isFunction
684  * @module ng
685  * @kind function
686  *
687  * @description
688  * Determines if a reference is a `Function`.
689  *
690  * @param {*} value Reference to check.
691  * @returns {boolean} True if `value` is a `Function`.
692  */
693 function isFunction(value) {return typeof value === 'function';}
694
695
696 /**
697  * Determines if a value is a regular expression object.
698  *
699  * @private
700  * @param {*} value Reference to check.
701  * @returns {boolean} True if `value` is a `RegExp`.
702  */
703 function isRegExp(value) {
704   return toString.call(value) === '[object RegExp]';
705 }
706
707
708 /**
709  * Checks if `obj` is a window object.
710  *
711  * @private
712  * @param {*} obj Object to check
713  * @returns {boolean} True if `obj` is a window obj.
714  */
715 function isWindow(obj) {
716   return obj && obj.window === obj;
717 }
718
719
720 function isScope(obj) {
721   return obj && obj.$evalAsync && obj.$watch;
722 }
723
724
725 function isFile(obj) {
726   return toString.call(obj) === '[object File]';
727 }
728
729
730 function isFormData(obj) {
731   return toString.call(obj) === '[object FormData]';
732 }
733
734
735 function isBlob(obj) {
736   return toString.call(obj) === '[object Blob]';
737 }
738
739
740 function isBoolean(value) {
741   return typeof value === 'boolean';
742 }
743
744
745 function isPromiseLike(obj) {
746   return obj && isFunction(obj.then);
747 }
748
749
750 var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
751 function isTypedArray(value) {
752   return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
753 }
754
755 function isArrayBuffer(obj) {
756   return toString.call(obj) === '[object ArrayBuffer]';
757 }
758
759
760 var trim = function(value) {
761   return isString(value) ? value.trim() : value;
762 };
763
764 // Copied from:
765 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
766 // Prereq: s is a string.
767 var escapeForRegexp = function(s) {
768   return s
769     .replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
770     // eslint-disable-next-line no-control-regex
771     .replace(/\x08/g, '\\x08');
772 };
773
774
775 /**
776  * @ngdoc function
777  * @name angular.isElement
778  * @module ng
779  * @kind function
780  *
781  * @description
782  * Determines if a reference is a DOM element (or wrapped jQuery element).
783  *
784  * @param {*} value Reference to check.
785  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
786  */
787 function isElement(node) {
788   return !!(node &&
789     (node.nodeName  // We are a direct element.
790     || (node.prop && node.attr && node.find)));  // We have an on and find method part of jQuery API.
791 }
792
793 /**
794  * @param str 'key1,key2,...'
795  * @returns {object} in the form of {key1:true, key2:true, ...}
796  */
797 function makeMap(str) {
798   var obj = {}, items = str.split(','), i;
799   for (i = 0; i < items.length; i++) {
800     obj[items[i]] = true;
801   }
802   return obj;
803 }
804
805
806 function nodeName_(element) {
807   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
808 }
809
810 function includes(array, obj) {
811   return Array.prototype.indexOf.call(array, obj) !== -1;
812 }
813
814 function arrayRemove(array, value) {
815   var index = array.indexOf(value);
816   if (index >= 0) {
817     array.splice(index, 1);
818   }
819   return index;
820 }
821
822 /**
823  * @ngdoc function
824  * @name angular.copy
825  * @module ng
826  * @kind function
827  *
828  * @description
829  * Creates a deep copy of `source`, which should be an object or an array.
830  *
831  * * If no destination is supplied, a copy of the object or array is created.
832  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
833  *   are deleted and then all elements/properties from the source are copied to it.
834  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
835  * * If `source` is identical to `destination` an exception will be thrown.
836  *
837  * <br />
838  * <div class="alert alert-warning">
839  *   Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
840  *   and on `destination`) will be ignored.
841  * </div>
842  *
843  * @param {*} source The source that will be used to make a copy.
844  *                   Can be any type, including primitives, `null`, and `undefined`.
845  * @param {(Object|Array)=} destination Destination into which the source is copied. If
846  *     provided, must be of the same type as `source`.
847  * @returns {*} The copy or updated `destination`, if `destination` was specified.
848  *
849  * @example
850   <example module="copyExample" name="angular-copy">
851     <file name="index.html">
852       <div ng-controller="ExampleController">
853         <form novalidate class="simple-form">
854           <label>Name: <input type="text" ng-model="user.name" /></label><br />
855           <label>Age:  <input type="number" ng-model="user.age" /></label><br />
856           Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
857                   <label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
858           <button ng-click="reset()">RESET</button>
859           <button ng-click="update(user)">SAVE</button>
860         </form>
861         <pre>form = {{user | json}}</pre>
862         <pre>master = {{master | json}}</pre>
863       </div>
864     </file>
865     <file name="script.js">
866       // Module: copyExample
867       angular.
868         module('copyExample', []).
869         controller('ExampleController', ['$scope', function($scope) {
870           $scope.master = {};
871
872           $scope.reset = function() {
873             // Example with 1 argument
874             $scope.user = angular.copy($scope.master);
875           };
876
877           $scope.update = function(user) {
878             // Example with 2 arguments
879             angular.copy(user, $scope.master);
880           };
881
882           $scope.reset();
883         }]);
884     </file>
885   </example>
886  */
887 function copy(source, destination) {
888   var stackSource = [];
889   var stackDest = [];
890
891   if (destination) {
892     if (isTypedArray(destination) || isArrayBuffer(destination)) {
893       throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.');
894     }
895     if (source === destination) {
896       throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.');
897     }
898
899     // Empty the destination object
900     if (isArray(destination)) {
901       destination.length = 0;
902     } else {
903       forEach(destination, function(value, key) {
904         if (key !== '$$hashKey') {
905           delete destination[key];
906         }
907       });
908     }
909
910     stackSource.push(source);
911     stackDest.push(destination);
912     return copyRecurse(source, destination);
913   }
914
915   return copyElement(source);
916
917   function copyRecurse(source, destination) {
918     var h = destination.$$hashKey;
919     var key;
920     if (isArray(source)) {
921       for (var i = 0, ii = source.length; i < ii; i++) {
922         destination.push(copyElement(source[i]));
923       }
924     } else if (isBlankObject(source)) {
925       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
926       for (key in source) {
927         destination[key] = copyElement(source[key]);
928       }
929     } else if (source && typeof source.hasOwnProperty === 'function') {
930       // Slow path, which must rely on hasOwnProperty
931       for (key in source) {
932         if (source.hasOwnProperty(key)) {
933           destination[key] = copyElement(source[key]);
934         }
935       }
936     } else {
937       // Slowest path --- hasOwnProperty can't be called as a method
938       for (key in source) {
939         if (hasOwnProperty.call(source, key)) {
940           destination[key] = copyElement(source[key]);
941         }
942       }
943     }
944     setHashKey(destination, h);
945     return destination;
946   }
947
948   function copyElement(source) {
949     // Simple values
950     if (!isObject(source)) {
951       return source;
952     }
953
954     // Already copied values
955     var index = stackSource.indexOf(source);
956     if (index !== -1) {
957       return stackDest[index];
958     }
959
960     if (isWindow(source) || isScope(source)) {
961       throw ngMinErr('cpws',
962         'Can\'t copy! Making copies of Window or Scope instances is not supported.');
963     }
964
965     var needsRecurse = false;
966     var destination = copyType(source);
967
968     if (destination === undefined) {
969       destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
970       needsRecurse = true;
971     }
972
973     stackSource.push(source);
974     stackDest.push(destination);
975
976     return needsRecurse
977       ? copyRecurse(source, destination)
978       : destination;
979   }
980
981   function copyType(source) {
982     switch (toString.call(source)) {
983       case '[object Int8Array]':
984       case '[object Int16Array]':
985       case '[object Int32Array]':
986       case '[object Float32Array]':
987       case '[object Float64Array]':
988       case '[object Uint8Array]':
989       case '[object Uint8ClampedArray]':
990       case '[object Uint16Array]':
991       case '[object Uint32Array]':
992         return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
993
994       case '[object ArrayBuffer]':
995         // Support: IE10
996         if (!source.slice) {
997           // If we're in this case we know the environment supports ArrayBuffer
998           /* eslint-disable no-undef */
999           var copied = new ArrayBuffer(source.byteLength);
1000           new Uint8Array(copied).set(new Uint8Array(source));
1001           /* eslint-enable */
1002           return copied;
1003         }
1004         return source.slice(0);
1005
1006       case '[object Boolean]':
1007       case '[object Number]':
1008       case '[object String]':
1009       case '[object Date]':
1010         return new source.constructor(source.valueOf());
1011
1012       case '[object RegExp]':
1013         var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
1014         re.lastIndex = source.lastIndex;
1015         return re;
1016
1017       case '[object Blob]':
1018         return new source.constructor([source], {type: source.type});
1019     }
1020
1021     if (isFunction(source.cloneNode)) {
1022       return source.cloneNode(true);
1023     }
1024   }
1025 }
1026
1027
1028 /**
1029  * @ngdoc function
1030  * @name angular.equals
1031  * @module ng
1032  * @kind function
1033  *
1034  * @description
1035  * Determines if two objects or two values are equivalent. Supports value types, regular
1036  * expressions, arrays and objects.
1037  *
1038  * Two objects or values are considered equivalent if at least one of the following is true:
1039  *
1040  * * Both objects or values pass `===` comparison.
1041  * * Both objects or values are of the same type and all of their properties are equal by
1042  *   comparing them with `angular.equals`.
1043  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1044  * * Both values represent the same regular expression (In JavaScript,
1045  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1046  *   representation matches).
1047  *
1048  * During a property comparison, properties of `function` type and properties with names
1049  * that begin with `$` are ignored.
1050  *
1051  * Scope and DOMWindow objects are being compared only by identify (`===`).
1052  *
1053  * @param {*} o1 Object or value to compare.
1054  * @param {*} o2 Object or value to compare.
1055  * @returns {boolean} True if arguments are equal.
1056  *
1057  * @example
1058    <example module="equalsExample" name="equalsExample">
1059      <file name="index.html">
1060       <div ng-controller="ExampleController">
1061         <form novalidate>
1062           <h3>User 1</h3>
1063           Name: <input type="text" ng-model="user1.name">
1064           Age: <input type="number" ng-model="user1.age">
1065
1066           <h3>User 2</h3>
1067           Name: <input type="text" ng-model="user2.name">
1068           Age: <input type="number" ng-model="user2.age">
1069
1070           <div>
1071             <br/>
1072             <input type="button" value="Compare" ng-click="compare()">
1073           </div>
1074           User 1: <pre>{{user1 | json}}</pre>
1075           User 2: <pre>{{user2 | json}}</pre>
1076           Equal: <pre>{{result}}</pre>
1077         </form>
1078       </div>
1079     </file>
1080     <file name="script.js">
1081         angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
1082           $scope.user1 = {};
1083           $scope.user2 = {};
1084           $scope.compare = function() {
1085             $scope.result = angular.equals($scope.user1, $scope.user2);
1086           };
1087         }]);
1088     </file>
1089   </example>
1090  */
1091 function equals(o1, o2) {
1092   if (o1 === o2) return true;
1093   if (o1 === null || o2 === null) return false;
1094   // eslint-disable-next-line no-self-compare
1095   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1096   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1097   if (t1 === t2 && t1 === 'object') {
1098     if (isArray(o1)) {
1099       if (!isArray(o2)) return false;
1100       if ((length = o1.length) === o2.length) {
1101         for (key = 0; key < length; key++) {
1102           if (!equals(o1[key], o2[key])) return false;
1103         }
1104         return true;
1105       }
1106     } else if (isDate(o1)) {
1107       if (!isDate(o2)) return false;
1108       return equals(o1.getTime(), o2.getTime());
1109     } else if (isRegExp(o1)) {
1110       if (!isRegExp(o2)) return false;
1111       return o1.toString() === o2.toString();
1112     } else {
1113       if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1114         isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1115       keySet = createMap();
1116       for (key in o1) {
1117         if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1118         if (!equals(o1[key], o2[key])) return false;
1119         keySet[key] = true;
1120       }
1121       for (key in o2) {
1122         if (!(key in keySet) &&
1123             key.charAt(0) !== '$' &&
1124             isDefined(o2[key]) &&
1125             !isFunction(o2[key])) return false;
1126       }
1127       return true;
1128     }
1129   }
1130   return false;
1131 }
1132
1133 var csp = function() {
1134   if (!isDefined(csp.rules)) {
1135
1136
1137     var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1138                     window.document.querySelector('[data-ng-csp]'));
1139
1140     if (ngCspElement) {
1141       var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1142                     ngCspElement.getAttribute('data-ng-csp');
1143       csp.rules = {
1144         noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1145         noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1146       };
1147     } else {
1148       csp.rules = {
1149         noUnsafeEval: noUnsafeEval(),
1150         noInlineStyle: false
1151       };
1152     }
1153   }
1154
1155   return csp.rules;
1156
1157   function noUnsafeEval() {
1158     try {
1159       // eslint-disable-next-line no-new, no-new-func
1160       new Function('');
1161       return false;
1162     } catch (e) {
1163       return true;
1164     }
1165   }
1166 };
1167
1168 /**
1169  * @ngdoc directive
1170  * @module ng
1171  * @name ngJq
1172  *
1173  * @element ANY
1174  * @param {string=} ngJq the name of the library available under `window`
1175  * to be used for angular.element
1176  * @description
1177  * Use this directive to force the angular.element library.  This should be
1178  * used to force either jqLite by leaving ng-jq blank or setting the name of
1179  * the jquery variable under window (eg. jQuery).
1180  *
1181  * Since angular looks for this directive when it is loaded (doesn't wait for the
1182  * DOMContentLoaded event), it must be placed on an element that comes before the script
1183  * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1184  * others ignored.
1185  *
1186  * @example
1187  * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1188  ```html
1189  <!doctype html>
1190  <html ng-app ng-jq>
1191  ...
1192  ...
1193  </html>
1194  ```
1195  * @example
1196  * This example shows how to use a jQuery based library of a different name.
1197  * The library name must be available at the top most 'window'.
1198  ```html
1199  <!doctype html>
1200  <html ng-app ng-jq="jQueryLib">
1201  ...
1202  ...
1203  </html>
1204  ```
1205  */
1206 var jq = function() {
1207   if (isDefined(jq.name_)) return jq.name_;
1208   var el;
1209   var i, ii = ngAttrPrefixes.length, prefix, name;
1210   for (i = 0; i < ii; ++i) {
1211     prefix = ngAttrPrefixes[i];
1212     el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]');
1213     if (el) {
1214       name = el.getAttribute(prefix + 'jq');
1215       break;
1216     }
1217   }
1218
1219   return (jq.name_ = name);
1220 };
1221
1222 function concat(array1, array2, index) {
1223   return array1.concat(slice.call(array2, index));
1224 }
1225
1226 function sliceArgs(args, startIndex) {
1227   return slice.call(args, startIndex || 0);
1228 }
1229
1230
1231 /**
1232  * @ngdoc function
1233  * @name angular.bind
1234  * @module ng
1235  * @kind function
1236  *
1237  * @description
1238  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1239  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1240  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1241  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1242  *
1243  * @param {Object} self Context which `fn` should be evaluated in.
1244  * @param {function()} fn Function to be bound.
1245  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1246  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1247  */
1248 function bind(self, fn) {
1249   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1250   if (isFunction(fn) && !(fn instanceof RegExp)) {
1251     return curryArgs.length
1252       ? function() {
1253           return arguments.length
1254             ? fn.apply(self, concat(curryArgs, arguments, 0))
1255             : fn.apply(self, curryArgs);
1256         }
1257       : function() {
1258           return arguments.length
1259             ? fn.apply(self, arguments)
1260             : fn.call(self);
1261         };
1262   } else {
1263     // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
1264     return fn;
1265   }
1266 }
1267
1268
1269 function toJsonReplacer(key, value) {
1270   var val = value;
1271
1272   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1273     val = undefined;
1274   } else if (isWindow(value)) {
1275     val = '$WINDOW';
1276   } else if (value &&  window.document === value) {
1277     val = '$DOCUMENT';
1278   } else if (isScope(value)) {
1279     val = '$SCOPE';
1280   }
1281
1282   return val;
1283 }
1284
1285
1286 /**
1287  * @ngdoc function
1288  * @name angular.toJson
1289  * @module ng
1290  * @kind function
1291  *
1292  * @description
1293  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1294  * stripped since angular uses this notation internally.
1295  *
1296  * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON.
1297  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1298  *    If set to an integer, the JSON output will contain that many spaces per indentation.
1299  * @returns {string|undefined} JSON-ified string representing `obj`.
1300  * @knownIssue
1301  *
1302  * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
1303  * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
1304  * `Date.prototype.toJSON` method as follows:
1305  *
1306  * ```
1307  * var _DatetoJSON = Date.prototype.toJSON;
1308  * Date.prototype.toJSON = function() {
1309  *   try {
1310  *     return _DatetoJSON.call(this);
1311  *   } catch(e) {
1312  *     if (e instanceof RangeError) {
1313  *       return null;
1314  *     }
1315  *     throw e;
1316  *   }
1317  * };
1318  * ```
1319  *
1320  * See https://github.com/angular/angular.js/pull/14221 for more information.
1321  */
1322 function toJson(obj, pretty) {
1323   if (isUndefined(obj)) return undefined;
1324   if (!isNumber(pretty)) {
1325     pretty = pretty ? 2 : null;
1326   }
1327   return JSON.stringify(obj, toJsonReplacer, pretty);
1328 }
1329
1330
1331 /**
1332  * @ngdoc function
1333  * @name angular.fromJson
1334  * @module ng
1335  * @kind function
1336  *
1337  * @description
1338  * Deserializes a JSON string.
1339  *
1340  * @param {string} json JSON string to deserialize.
1341  * @returns {Object|Array|string|number} Deserialized JSON string.
1342  */
1343 function fromJson(json) {
1344   return isString(json)
1345       ? JSON.parse(json)
1346       : json;
1347 }
1348
1349
1350 var ALL_COLONS = /:/g;
1351 function timezoneToOffset(timezone, fallback) {
1352   // IE/Edge do not "understand" colon (`:`) in timezone
1353   timezone = timezone.replace(ALL_COLONS, '');
1354   var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1355   return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1356 }
1357
1358
1359 function addDateMinutes(date, minutes) {
1360   date = new Date(date.getTime());
1361   date.setMinutes(date.getMinutes() + minutes);
1362   return date;
1363 }
1364
1365
1366 function convertTimezoneToLocal(date, timezone, reverse) {
1367   reverse = reverse ? -1 : 1;
1368   var dateTimezoneOffset = date.getTimezoneOffset();
1369   var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1370   return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
1371 }
1372
1373
1374 /**
1375  * @returns {string} Returns the string representation of the element.
1376  */
1377 function startingTag(element) {
1378   element = jqLite(element).clone();
1379   try {
1380     // turns out IE does not let you set .html() on elements which
1381     // are not allowed to have children. So we just ignore it.
1382     element.empty();
1383   } catch (e) { /* empty */ }
1384   var elemHtml = jqLite('<div>').append(element).html();
1385   try {
1386     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1387         elemHtml.
1388           match(/^(<[^>]+>)/)[1].
1389           replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
1390   } catch (e) {
1391     return lowercase(elemHtml);
1392   }
1393
1394 }
1395
1396
1397 /////////////////////////////////////////////////
1398
1399 /**
1400  * Tries to decode the URI component without throwing an exception.
1401  *
1402  * @private
1403  * @param str value potential URI component to check.
1404  * @returns {boolean} True if `value` can be decoded
1405  * with the decodeURIComponent function.
1406  */
1407 function tryDecodeURIComponent(value) {
1408   try {
1409     return decodeURIComponent(value);
1410   } catch (e) {
1411     // Ignore any invalid uri component.
1412   }
1413 }
1414
1415
1416 /**
1417  * Parses an escaped url query string into key-value pairs.
1418  * @returns {Object.<string,boolean|Array>}
1419  */
1420 function parseKeyValue(/**string*/keyValue) {
1421   var obj = {};
1422   forEach((keyValue || '').split('&'), function(keyValue) {
1423     var splitPoint, key, val;
1424     if (keyValue) {
1425       key = keyValue = keyValue.replace(/\+/g,'%20');
1426       splitPoint = keyValue.indexOf('=');
1427       if (splitPoint !== -1) {
1428         key = keyValue.substring(0, splitPoint);
1429         val = keyValue.substring(splitPoint + 1);
1430       }
1431       key = tryDecodeURIComponent(key);
1432       if (isDefined(key)) {
1433         val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1434         if (!hasOwnProperty.call(obj, key)) {
1435           obj[key] = val;
1436         } else if (isArray(obj[key])) {
1437           obj[key].push(val);
1438         } else {
1439           obj[key] = [obj[key],val];
1440         }
1441       }
1442     }
1443   });
1444   return obj;
1445 }
1446
1447 function toKeyValue(obj) {
1448   var parts = [];
1449   forEach(obj, function(value, key) {
1450     if (isArray(value)) {
1451       forEach(value, function(arrayValue) {
1452         parts.push(encodeUriQuery(key, true) +
1453                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1454       });
1455     } else {
1456     parts.push(encodeUriQuery(key, true) +
1457                (value === true ? '' : '=' + encodeUriQuery(value, true)));
1458     }
1459   });
1460   return parts.length ? parts.join('&') : '';
1461 }
1462
1463
1464 /**
1465  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1466  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1467  * segments:
1468  *    segment       = *pchar
1469  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1470  *    pct-encoded   = "%" HEXDIG HEXDIG
1471  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1472  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1473  *                     / "*" / "+" / "," / ";" / "="
1474  */
1475 function encodeUriSegment(val) {
1476   return encodeUriQuery(val, true).
1477              replace(/%26/gi, '&').
1478              replace(/%3D/gi, '=').
1479              replace(/%2B/gi, '+');
1480 }
1481
1482
1483 /**
1484  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1485  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1486  * encoded per http://tools.ietf.org/html/rfc3986:
1487  *    query       = *( pchar / "/" / "?" )
1488  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1489  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1490  *    pct-encoded   = "%" HEXDIG HEXDIG
1491  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1492  *                     / "*" / "+" / "," / ";" / "="
1493  */
1494 function encodeUriQuery(val, pctEncodeSpaces) {
1495   return encodeURIComponent(val).
1496              replace(/%40/gi, '@').
1497              replace(/%3A/gi, ':').
1498              replace(/%24/g, '$').
1499              replace(/%2C/gi, ',').
1500              replace(/%3B/gi, ';').
1501              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1502 }
1503
1504 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1505
1506 function getNgAttribute(element, ngAttr) {
1507   var attr, i, ii = ngAttrPrefixes.length;
1508   for (i = 0; i < ii; ++i) {
1509     attr = ngAttrPrefixes[i] + ngAttr;
1510     if (isString(attr = element.getAttribute(attr))) {
1511       return attr;
1512     }
1513   }
1514   return null;
1515 }
1516
1517 function allowAutoBootstrap(document) {
1518   if (!document.currentScript) {
1519     return true;
1520   }
1521   var src = document.currentScript.getAttribute('src');
1522   var link = document.createElement('a');
1523   link.href = src;
1524   if (document.location.origin === link.origin) {
1525     // Same-origin resources are always allowed, even for non-whitelisted schemes.
1526     return true;
1527   }
1528   // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
1529   // This is to prevent angular.js bundled with browser extensions from being used to bypass the
1530   // content security policy in web pages and other browser extensions.
1531   switch (link.protocol) {
1532     case 'http:':
1533     case 'https:':
1534     case 'ftp:':
1535     case 'blob:':
1536     case 'file:':
1537     case 'data:':
1538       return true;
1539     default:
1540       return false;
1541   }
1542 }
1543
1544 // Cached as it has to run during loading so that document.currentScript is available.
1545 var isAutoBootstrapAllowed = allowAutoBootstrap(window.document);
1546
1547 /**
1548  * @ngdoc directive
1549  * @name ngApp
1550  * @module ng
1551  *
1552  * @element ANY
1553  * @param {angular.Module} ngApp an optional application
1554  *   {@link angular.module module} name to load.
1555  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1556  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1557  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1558  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1559  *   tracking down the root of these bugs.
1560  *
1561  * @description
1562  *
1563  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1564  * designates the **root element** of the application and is typically placed near the root element
1565  * of the page - e.g. on the `<body>` or `<html>` tags.
1566  *
1567  * There are a few things to keep in mind when using `ngApp`:
1568  * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1569  *   found in the document will be used to define the root element to auto-bootstrap as an
1570  *   application. To run multiple applications in an HTML document you must manually bootstrap them using
1571  *   {@link angular.bootstrap} instead.
1572  * - AngularJS applications cannot be nested within each other.
1573  * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
1574  *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
1575  *   {@link ngRoute.ngView `ngView`}.
1576  *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1577  *   causing animations to stop working and making the injector inaccessible from outside the app.
1578  *
1579  * You can specify an **AngularJS module** to be used as the root module for the application.  This
1580  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1581  * should contain the application code needed or have dependencies on other modules that will
1582  * contain the code. See {@link angular.module} for more information.
1583  *
1584  * In the example below if the `ngApp` directive were not placed on the `html` element then the
1585  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1586  * would not be resolved to `3`.
1587  *
1588  * `ngApp` is the easiest, and most common way to bootstrap an application.
1589  *
1590  <example module="ngAppDemo" name="ng-app">
1591    <file name="index.html">
1592    <div ng-controller="ngAppDemoController">
1593      I can add: {{a}} + {{b}} =  {{ a+b }}
1594    </div>
1595    </file>
1596    <file name="script.js">
1597    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1598      $scope.a = 1;
1599      $scope.b = 2;
1600    });
1601    </file>
1602  </example>
1603  *
1604  * Using `ngStrictDi`, you would see something like this:
1605  *
1606  <example ng-app-included="true" name="strict-di">
1607    <file name="index.html">
1608    <div ng-app="ngAppStrictDemo" ng-strict-di>
1609        <div ng-controller="GoodController1">
1610            I can add: {{a}} + {{b}} =  {{ a+b }}
1611
1612            <p>This renders because the controller does not fail to
1613               instantiate, by using explicit annotation style (see
1614               script.js for details)
1615            </p>
1616        </div>
1617
1618        <div ng-controller="GoodController2">
1619            Name: <input ng-model="name"><br />
1620            Hello, {{name}}!
1621
1622            <p>This renders because the controller does not fail to
1623               instantiate, by using explicit annotation style
1624               (see script.js for details)
1625            </p>
1626        </div>
1627
1628        <div ng-controller="BadController">
1629            I can add: {{a}} + {{b}} =  {{ a+b }}
1630
1631            <p>The controller could not be instantiated, due to relying
1632               on automatic function annotations (which are disabled in
1633               strict mode). As such, the content of this section is not
1634               interpolated, and there should be an error in your web console.
1635            </p>
1636        </div>
1637    </div>
1638    </file>
1639    <file name="script.js">
1640    angular.module('ngAppStrictDemo', [])
1641      // BadController will fail to instantiate, due to relying on automatic function annotation,
1642      // rather than an explicit annotation
1643      .controller('BadController', function($scope) {
1644        $scope.a = 1;
1645        $scope.b = 2;
1646      })
1647      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1648      // due to using explicit annotations using the array style and $inject property, respectively.
1649      .controller('GoodController1', ['$scope', function($scope) {
1650        $scope.a = 1;
1651        $scope.b = 2;
1652      }])
1653      .controller('GoodController2', GoodController2);
1654      function GoodController2($scope) {
1655        $scope.name = 'World';
1656      }
1657      GoodController2.$inject = ['$scope'];
1658    </file>
1659    <file name="style.css">
1660    div[ng-controller] {
1661        margin-bottom: 1em;
1662        -webkit-border-radius: 4px;
1663        border-radius: 4px;
1664        border: 1px solid;
1665        padding: .5em;
1666    }
1667    div[ng-controller^=Good] {
1668        border-color: #d6e9c6;
1669        background-color: #dff0d8;
1670        color: #3c763d;
1671    }
1672    div[ng-controller^=Bad] {
1673        border-color: #ebccd1;
1674        background-color: #f2dede;
1675        color: #a94442;
1676        margin-bottom: 0;
1677    }
1678    </file>
1679  </example>
1680  */
1681 function angularInit(element, bootstrap) {
1682   var appElement,
1683       module,
1684       config = {};
1685
1686   // The element `element` has priority over any other element.
1687   forEach(ngAttrPrefixes, function(prefix) {
1688     var name = prefix + 'app';
1689
1690     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1691       appElement = element;
1692       module = element.getAttribute(name);
1693     }
1694   });
1695   forEach(ngAttrPrefixes, function(prefix) {
1696     var name = prefix + 'app';
1697     var candidate;
1698
1699     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1700       appElement = candidate;
1701       module = candidate.getAttribute(name);
1702     }
1703   });
1704   if (appElement) {
1705     if (!isAutoBootstrapAllowed) {
1706       window.console.error('Angular: disabling automatic bootstrap. <script> protocol indicates ' +
1707           'an extension, document.location.href does not match.');
1708       return;
1709     }
1710     config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
1711     bootstrap(appElement, module ? [module] : [], config);
1712   }
1713 }
1714
1715 /**
1716  * @ngdoc function
1717  * @name angular.bootstrap
1718  * @module ng
1719  * @description
1720  * Use this function to manually start up angular application.
1721  *
1722  * For more information, see the {@link guide/bootstrap Bootstrap guide}.
1723  *
1724  * Angular will detect if it has been loaded into the browser more than once and only allow the
1725  * first loaded script to be bootstrapped and will report a warning to the browser console for
1726  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1727  * multiple instances of Angular try to work on the DOM.
1728  *
1729  * <div class="alert alert-warning">
1730  * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
1731  * They must use {@link ng.directive:ngApp ngApp}.
1732  * </div>
1733  *
1734  * <div class="alert alert-warning">
1735  * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
1736  * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
1737  * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1738  * causing animations to stop working and making the injector inaccessible from outside the app.
1739  * </div>
1740  *
1741  * ```html
1742  * <!doctype html>
1743  * <html>
1744  * <body>
1745  * <div ng-controller="WelcomeController">
1746  *   {{greeting}}
1747  * </div>
1748  *
1749  * <script src="angular.js"></script>
1750  * <script>
1751  *   var app = angular.module('demo', [])
1752  *   .controller('WelcomeController', function($scope) {
1753  *       $scope.greeting = 'Welcome!';
1754  *   });
1755  *   angular.bootstrap(document, ['demo']);
1756  * </script>
1757  * </body>
1758  * </html>
1759  * ```
1760  *
1761  * @param {DOMElement} element DOM element which is the root of angular application.
1762  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1763  *     Each item in the array should be the name of a predefined module or a (DI annotated)
1764  *     function that will be invoked by the injector as a `config` block.
1765  *     See: {@link angular.module modules}
1766  * @param {Object=} config an object for defining configuration options for the application. The
1767  *     following keys are supported:
1768  *
1769  * * `strictDi` - disable automatic function annotation for the application. This is meant to
1770  *   assist in finding bugs which break minified code. Defaults to `false`.
1771  *
1772  * @returns {auto.$injector} Returns the newly created injector for this app.
1773  */
1774 function bootstrap(element, modules, config) {
1775   if (!isObject(config)) config = {};
1776   var defaultConfig = {
1777     strictDi: false
1778   };
1779   config = extend(defaultConfig, config);
1780   var doBootstrap = function() {
1781     element = jqLite(element);
1782
1783     if (element.injector()) {
1784       var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1785       // Encode angle brackets to prevent input from being sanitized to empty string #8683.
1786       throw ngMinErr(
1787           'btstrpd',
1788           'App already bootstrapped with this element \'{0}\'',
1789           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1790     }
1791
1792     modules = modules || [];
1793     modules.unshift(['$provide', function($provide) {
1794       $provide.value('$rootElement', element);
1795     }]);
1796
1797     if (config.debugInfoEnabled) {
1798       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1799       modules.push(['$compileProvider', function($compileProvider) {
1800         $compileProvider.debugInfoEnabled(true);
1801       }]);
1802     }
1803
1804     modules.unshift('ng');
1805     var injector = createInjector(modules, config.strictDi);
1806     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1807        function bootstrapApply(scope, element, compile, injector) {
1808         scope.$apply(function() {
1809           element.data('$injector', injector);
1810           compile(element)(scope);
1811         });
1812       }]
1813     );
1814     return injector;
1815   };
1816
1817   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1818   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1819
1820   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1821     config.debugInfoEnabled = true;
1822     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1823   }
1824
1825   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1826     return doBootstrap();
1827   }
1828
1829   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1830   angular.resumeBootstrap = function(extraModules) {
1831     forEach(extraModules, function(module) {
1832       modules.push(module);
1833     });
1834     return doBootstrap();
1835   };
1836
1837   if (isFunction(angular.resumeDeferredBootstrap)) {
1838     angular.resumeDeferredBootstrap();
1839   }
1840 }
1841
1842 /**
1843  * @ngdoc function
1844  * @name angular.reloadWithDebugInfo
1845  * @module ng
1846  * @description
1847  * Use this function to reload the current application with debug information turned on.
1848  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1849  *
1850  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1851  */
1852 function reloadWithDebugInfo() {
1853   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1854   window.location.reload();
1855 }
1856
1857 /**
1858  * @name angular.getTestability
1859  * @module ng
1860  * @description
1861  * Get the testability service for the instance of Angular on the given
1862  * element.
1863  * @param {DOMElement} element DOM element which is the root of angular application.
1864  */
1865 function getTestability(rootElement) {
1866   var injector = angular.element(rootElement).injector();
1867   if (!injector) {
1868     throw ngMinErr('test',
1869       'no injector found for element argument to getTestability');
1870   }
1871   return injector.get('$$testability');
1872 }
1873
1874 var SNAKE_CASE_REGEXP = /[A-Z]/g;
1875 function snake_case(name, separator) {
1876   separator = separator || '_';
1877   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1878     return (pos ? separator : '') + letter.toLowerCase();
1879   });
1880 }
1881
1882 var bindJQueryFired = false;
1883 function bindJQuery() {
1884   var originalCleanData;
1885
1886   if (bindJQueryFired) {
1887     return;
1888   }
1889
1890   // bind to jQuery if present;
1891   var jqName = jq();
1892   jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
1893            !jqName             ? undefined     :   // use jqLite
1894                                  window[jqName];   // use jQuery specified by `ngJq`
1895
1896   // Use jQuery if it exists with proper functionality, otherwise default to us.
1897   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1898   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1899   // versions. It will not work for sure with jQuery <1.7, though.
1900   if (jQuery && jQuery.fn.on) {
1901     jqLite = jQuery;
1902     extend(jQuery.fn, {
1903       scope: JQLitePrototype.scope,
1904       isolateScope: JQLitePrototype.isolateScope,
1905       controller: JQLitePrototype.controller,
1906       injector: JQLitePrototype.injector,
1907       inheritedData: JQLitePrototype.inheritedData
1908     });
1909
1910     // All nodes removed from the DOM via various jQuery APIs like .remove()
1911     // are passed through jQuery.cleanData. Monkey-patch this method to fire
1912     // the $destroy event on all removed nodes.
1913     originalCleanData = jQuery.cleanData;
1914     jQuery.cleanData = function(elems) {
1915       var events;
1916       for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1917         events = jQuery._data(elem, 'events');
1918         if (events && events.$destroy) {
1919           jQuery(elem).triggerHandler('$destroy');
1920         }
1921       }
1922       originalCleanData(elems);
1923     };
1924   } else {
1925     jqLite = JQLite;
1926   }
1927
1928   angular.element = jqLite;
1929
1930   // Prevent double-proxying.
1931   bindJQueryFired = true;
1932 }
1933
1934 /**
1935  * throw error if the argument is falsy.
1936  */
1937 function assertArg(arg, name, reason) {
1938   if (!arg) {
1939     throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
1940   }
1941   return arg;
1942 }
1943
1944 function assertArgFn(arg, name, acceptArrayAnnotation) {
1945   if (acceptArrayAnnotation && isArray(arg)) {
1946       arg = arg[arg.length - 1];
1947   }
1948
1949   assertArg(isFunction(arg), name, 'not a function, got ' +
1950       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1951   return arg;
1952 }
1953
1954 /**
1955  * throw error if the name given is hasOwnProperty
1956  * @param  {String} name    the name to test
1957  * @param  {String} context the context in which the name is used, such as module or directive
1958  */
1959 function assertNotHasOwnProperty(name, context) {
1960   if (name === 'hasOwnProperty') {
1961     throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1962   }
1963 }
1964
1965 /**
1966  * Return the value accessible from the object by path. Any undefined traversals are ignored
1967  * @param {Object} obj starting object
1968  * @param {String} path path to traverse
1969  * @param {boolean} [bindFnToScope=true]
1970  * @returns {Object} value as accessible by path
1971  */
1972 //TODO(misko): this function needs to be removed
1973 function getter(obj, path, bindFnToScope) {
1974   if (!path) return obj;
1975   var keys = path.split('.');
1976   var key;
1977   var lastInstance = obj;
1978   var len = keys.length;
1979
1980   for (var i = 0; i < len; i++) {
1981     key = keys[i];
1982     if (obj) {
1983       obj = (lastInstance = obj)[key];
1984     }
1985   }
1986   if (!bindFnToScope && isFunction(obj)) {
1987     return bind(lastInstance, obj);
1988   }
1989   return obj;
1990 }
1991
1992 /**
1993  * Return the DOM siblings between the first and last node in the given array.
1994  * @param {Array} array like object
1995  * @returns {Array} the inputted object or a jqLite collection containing the nodes
1996  */
1997 function getBlockNodes(nodes) {
1998   // TODO(perf): update `nodes` instead of creating a new object?
1999   var node = nodes[0];
2000   var endNode = nodes[nodes.length - 1];
2001   var blockNodes;
2002
2003   for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
2004     if (blockNodes || nodes[i] !== node) {
2005       if (!blockNodes) {
2006         blockNodes = jqLite(slice.call(nodes, 0, i));
2007       }
2008       blockNodes.push(node);
2009     }
2010   }
2011
2012   return blockNodes || nodes;
2013 }
2014
2015
2016 /**
2017  * Creates a new object without a prototype. This object is useful for lookup without having to
2018  * guard against prototypically inherited properties via hasOwnProperty.
2019  *
2020  * Related micro-benchmarks:
2021  * - http://jsperf.com/object-create2
2022  * - http://jsperf.com/proto-map-lookup/2
2023  * - http://jsperf.com/for-in-vs-object-keys2
2024  *
2025  * @returns {Object}
2026  */
2027 function createMap() {
2028   return Object.create(null);
2029 }
2030
2031 var NODE_TYPE_ELEMENT = 1;
2032 var NODE_TYPE_ATTRIBUTE = 2;
2033 var NODE_TYPE_TEXT = 3;
2034 var NODE_TYPE_COMMENT = 8;
2035 var NODE_TYPE_DOCUMENT = 9;
2036 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
2037
2038 /**
2039  * @ngdoc type
2040  * @name angular.Module
2041  * @module ng
2042  * @description
2043  *
2044  * Interface for configuring angular {@link angular.module modules}.
2045  */
2046
2047 function setupModuleLoader(window) {
2048
2049   var $injectorMinErr = minErr('$injector');
2050   var ngMinErr = minErr('ng');
2051
2052   function ensure(obj, name, factory) {
2053     return obj[name] || (obj[name] = factory());
2054   }
2055
2056   var angular = ensure(window, 'angular', Object);
2057
2058   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2059   angular.$$minErr = angular.$$minErr || minErr;
2060
2061   return ensure(angular, 'module', function() {
2062     /** @type {Object.<string, angular.Module>} */
2063     var modules = {};
2064
2065     /**
2066      * @ngdoc function
2067      * @name angular.module
2068      * @module ng
2069      * @description
2070      *
2071      * The `angular.module` is a global place for creating, registering and retrieving Angular
2072      * modules.
2073      * All modules (angular core or 3rd party) that should be available to an application must be
2074      * registered using this mechanism.
2075      *
2076      * Passing one argument retrieves an existing {@link angular.Module},
2077      * whereas passing more than one argument creates a new {@link angular.Module}
2078      *
2079      *
2080      * # Module
2081      *
2082      * A module is a collection of services, directives, controllers, filters, and configuration information.
2083      * `angular.module` is used to configure the {@link auto.$injector $injector}.
2084      *
2085      * ```js
2086      * // Create a new module
2087      * var myModule = angular.module('myModule', []);
2088      *
2089      * // register a new service
2090      * myModule.value('appName', 'MyCoolApp');
2091      *
2092      * // configure existing services inside initialization blocks.
2093      * myModule.config(['$locationProvider', function($locationProvider) {
2094      *   // Configure existing providers
2095      *   $locationProvider.hashPrefix('!');
2096      * }]);
2097      * ```
2098      *
2099      * Then you can create an injector and load your modules like this:
2100      *
2101      * ```js
2102      * var injector = angular.injector(['ng', 'myModule'])
2103      * ```
2104      *
2105      * However it's more likely that you'll just use
2106      * {@link ng.directive:ngApp ngApp} or
2107      * {@link angular.bootstrap} to simplify this process for you.
2108      *
2109      * @param {!string} name The name of the module to create or retrieve.
2110      * @param {!Array.<string>=} requires If specified then new module is being created. If
2111      *        unspecified then the module is being retrieved for further configuration.
2112      * @param {Function=} configFn Optional configuration function for the module. Same as
2113      *        {@link angular.Module#config Module#config()}.
2114      * @returns {angular.Module} new module with the {@link angular.Module} api.
2115      */
2116     return function module(name, requires, configFn) {
2117       var assertNotHasOwnProperty = function(name, context) {
2118         if (name === 'hasOwnProperty') {
2119           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2120         }
2121       };
2122
2123       assertNotHasOwnProperty(name, 'module');
2124       if (requires && modules.hasOwnProperty(name)) {
2125         modules[name] = null;
2126       }
2127       return ensure(modules, name, function() {
2128         if (!requires) {
2129           throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
2130              'the module name or forgot to load it. If registering a module ensure that you ' +
2131              'specify the dependencies as the second argument.', name);
2132         }
2133
2134         /** @type {!Array.<Array.<*>>} */
2135         var invokeQueue = [];
2136
2137         /** @type {!Array.<Function>} */
2138         var configBlocks = [];
2139
2140         /** @type {!Array.<Function>} */
2141         var runBlocks = [];
2142
2143         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2144
2145         /** @type {angular.Module} */
2146         var moduleInstance = {
2147           // Private state
2148           _invokeQueue: invokeQueue,
2149           _configBlocks: configBlocks,
2150           _runBlocks: runBlocks,
2151
2152           /**
2153            * @ngdoc property
2154            * @name angular.Module#requires
2155            * @module ng
2156            *
2157            * @description
2158            * Holds the list of modules which the injector will load before the current module is
2159            * loaded.
2160            */
2161           requires: requires,
2162
2163           /**
2164            * @ngdoc property
2165            * @name angular.Module#name
2166            * @module ng
2167            *
2168            * @description
2169            * Name of the module.
2170            */
2171           name: name,
2172
2173
2174           /**
2175            * @ngdoc method
2176            * @name angular.Module#provider
2177            * @module ng
2178            * @param {string} name service name
2179            * @param {Function} providerType Construction function for creating new instance of the
2180            *                                service.
2181            * @description
2182            * See {@link auto.$provide#provider $provide.provider()}.
2183            */
2184           provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2185
2186           /**
2187            * @ngdoc method
2188            * @name angular.Module#factory
2189            * @module ng
2190            * @param {string} name service name
2191            * @param {Function} providerFunction Function for creating new instance of the service.
2192            * @description
2193            * See {@link auto.$provide#factory $provide.factory()}.
2194            */
2195           factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2196
2197           /**
2198            * @ngdoc method
2199            * @name angular.Module#service
2200            * @module ng
2201            * @param {string} name service name
2202            * @param {Function} constructor A constructor function that will be instantiated.
2203            * @description
2204            * See {@link auto.$provide#service $provide.service()}.
2205            */
2206           service: invokeLaterAndSetModuleName('$provide', 'service'),
2207
2208           /**
2209            * @ngdoc method
2210            * @name angular.Module#value
2211            * @module ng
2212            * @param {string} name service name
2213            * @param {*} object Service instance object.
2214            * @description
2215            * See {@link auto.$provide#value $provide.value()}.
2216            */
2217           value: invokeLater('$provide', 'value'),
2218
2219           /**
2220            * @ngdoc method
2221            * @name angular.Module#constant
2222            * @module ng
2223            * @param {string} name constant name
2224            * @param {*} object Constant value.
2225            * @description
2226            * Because the constants are fixed, they get applied before other provide methods.
2227            * See {@link auto.$provide#constant $provide.constant()}.
2228            */
2229           constant: invokeLater('$provide', 'constant', 'unshift'),
2230
2231            /**
2232            * @ngdoc method
2233            * @name angular.Module#decorator
2234            * @module ng
2235            * @param {string} name The name of the service to decorate.
2236            * @param {Function} decorFn This function will be invoked when the service needs to be
2237            *                           instantiated and should return the decorated service instance.
2238            * @description
2239            * See {@link auto.$provide#decorator $provide.decorator()}.
2240            */
2241           decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2242
2243           /**
2244            * @ngdoc method
2245            * @name angular.Module#animation
2246            * @module ng
2247            * @param {string} name animation name
2248            * @param {Function} animationFactory Factory function for creating new instance of an
2249            *                                    animation.
2250            * @description
2251            *
2252            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2253            *
2254            *
2255            * Defines an animation hook that can be later used with
2256            * {@link $animate $animate} service and directives that use this service.
2257            *
2258            * ```js
2259            * module.animation('.animation-name', function($inject1, $inject2) {
2260            *   return {
2261            *     eventName : function(element, done) {
2262            *       //code to run the animation
2263            *       //once complete, then run done()
2264            *       return function cancellationFunction(element) {
2265            *         //code to cancel the animation
2266            *       }
2267            *     }
2268            *   }
2269            * })
2270            * ```
2271            *
2272            * See {@link ng.$animateProvider#register $animateProvider.register()} and
2273            * {@link ngAnimate ngAnimate module} for more information.
2274            */
2275           animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2276
2277           /**
2278            * @ngdoc method
2279            * @name angular.Module#filter
2280            * @module ng
2281            * @param {string} name Filter name - this must be a valid angular expression identifier
2282            * @param {Function} filterFactory Factory function for creating new instance of filter.
2283            * @description
2284            * See {@link ng.$filterProvider#register $filterProvider.register()}.
2285            *
2286            * <div class="alert alert-warning">
2287            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2288            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2289            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2290            * (`myapp_subsection_filterx`).
2291            * </div>
2292            */
2293           filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2294
2295           /**
2296            * @ngdoc method
2297            * @name angular.Module#controller
2298            * @module ng
2299            * @param {string|Object} name Controller name, or an object map of controllers where the
2300            *    keys are the names and the values are the constructors.
2301            * @param {Function} constructor Controller constructor function.
2302            * @description
2303            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2304            */
2305           controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2306
2307           /**
2308            * @ngdoc method
2309            * @name angular.Module#directive
2310            * @module ng
2311            * @param {string|Object} name Directive name, or an object map of directives where the
2312            *    keys are the names and the values are the factories.
2313            * @param {Function} directiveFactory Factory function for creating new instance of
2314            * directives.
2315            * @description
2316            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2317            */
2318           directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2319
2320           /**
2321            * @ngdoc method
2322            * @name angular.Module#component
2323            * @module ng
2324            * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
2325            * @param {Object} options Component definition object (a simplified
2326            *    {@link ng.$compile#directive-definition-object directive definition object})
2327            *
2328            * @description
2329            * See {@link ng.$compileProvider#component $compileProvider.component()}.
2330            */
2331           component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
2332
2333           /**
2334            * @ngdoc method
2335            * @name angular.Module#config
2336            * @module ng
2337            * @param {Function} configFn Execute this function on module load. Useful for service
2338            *    configuration.
2339            * @description
2340            * Use this method to register work which needs to be performed on module loading.
2341            * For more about how to configure services, see
2342            * {@link providers#provider-recipe Provider Recipe}.
2343            */
2344           config: config,
2345
2346           /**
2347            * @ngdoc method
2348            * @name angular.Module#run
2349            * @module ng
2350            * @param {Function} initializationFn Execute this function after injector creation.
2351            *    Useful for application initialization.
2352            * @description
2353            * Use this method to register work which should be performed when the injector is done
2354            * loading all modules.
2355            */
2356           run: function(block) {
2357             runBlocks.push(block);
2358             return this;
2359           }
2360         };
2361
2362         if (configFn) {
2363           config(configFn);
2364         }
2365
2366         return moduleInstance;
2367
2368         /**
2369          * @param {string} provider
2370          * @param {string} method
2371          * @param {String=} insertMethod
2372          * @returns {angular.Module}
2373          */
2374         function invokeLater(provider, method, insertMethod, queue) {
2375           if (!queue) queue = invokeQueue;
2376           return function() {
2377             queue[insertMethod || 'push']([provider, method, arguments]);
2378             return moduleInstance;
2379           };
2380         }
2381
2382         /**
2383          * @param {string} provider
2384          * @param {string} method
2385          * @returns {angular.Module}
2386          */
2387         function invokeLaterAndSetModuleName(provider, method) {
2388           return function(recipeName, factoryFunction) {
2389             if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2390             invokeQueue.push([provider, method, arguments]);
2391             return moduleInstance;
2392           };
2393         }
2394       });
2395     };
2396   });
2397
2398 }
2399
2400 /* global shallowCopy: true */
2401
2402 /**
2403  * Creates a shallow copy of an object, an array or a primitive.
2404  *
2405  * Assumes that there are no proto properties for objects.
2406  */
2407 function shallowCopy(src, dst) {
2408   if (isArray(src)) {
2409     dst = dst || [];
2410
2411     for (var i = 0, ii = src.length; i < ii; i++) {
2412       dst[i] = src[i];
2413     }
2414   } else if (isObject(src)) {
2415     dst = dst || {};
2416
2417     for (var key in src) {
2418       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
2419         dst[key] = src[key];
2420       }
2421     }
2422   }
2423
2424   return dst || src;
2425 }
2426
2427 /* global toDebugString: true */
2428
2429 function serializeObject(obj) {
2430   var seen = [];
2431
2432   return JSON.stringify(obj, function(key, val) {
2433     val = toJsonReplacer(key, val);
2434     if (isObject(val)) {
2435
2436       if (seen.indexOf(val) >= 0) return '...';
2437
2438       seen.push(val);
2439     }
2440     return val;
2441   });
2442 }
2443
2444 function toDebugString(obj) {
2445   if (typeof obj === 'function') {
2446     return obj.toString().replace(/ \{[\s\S]*$/, '');
2447   } else if (isUndefined(obj)) {
2448     return 'undefined';
2449   } else if (typeof obj !== 'string') {
2450     return serializeObject(obj);
2451   }
2452   return obj;
2453 }
2454
2455 /* global angularModule: true,
2456   version: true,
2457
2458   $CompileProvider,
2459
2460   htmlAnchorDirective,
2461   inputDirective,
2462   inputDirective,
2463   formDirective,
2464   scriptDirective,
2465   selectDirective,
2466   optionDirective,
2467   ngBindDirective,
2468   ngBindHtmlDirective,
2469   ngBindTemplateDirective,
2470   ngClassDirective,
2471   ngClassEvenDirective,
2472   ngClassOddDirective,
2473   ngCloakDirective,
2474   ngControllerDirective,
2475   ngFormDirective,
2476   ngHideDirective,
2477   ngIfDirective,
2478   ngIncludeDirective,
2479   ngIncludeFillContentDirective,
2480   ngInitDirective,
2481   ngNonBindableDirective,
2482   ngPluralizeDirective,
2483   ngRepeatDirective,
2484   ngShowDirective,
2485   ngStyleDirective,
2486   ngSwitchDirective,
2487   ngSwitchWhenDirective,
2488   ngSwitchDefaultDirective,
2489   ngOptionsDirective,
2490   ngTranscludeDirective,
2491   ngModelDirective,
2492   ngListDirective,
2493   ngChangeDirective,
2494   patternDirective,
2495   patternDirective,
2496   requiredDirective,
2497   requiredDirective,
2498   minlengthDirective,
2499   minlengthDirective,
2500   maxlengthDirective,
2501   maxlengthDirective,
2502   ngValueDirective,
2503   ngModelOptionsDirective,
2504   ngAttributeAliasDirectives,
2505   ngEventDirectives,
2506
2507   $AnchorScrollProvider,
2508   $AnimateProvider,
2509   $CoreAnimateCssProvider,
2510   $$CoreAnimateJsProvider,
2511   $$CoreAnimateQueueProvider,
2512   $$AnimateRunnerFactoryProvider,
2513   $$AnimateAsyncRunFactoryProvider,
2514   $BrowserProvider,
2515   $CacheFactoryProvider,
2516   $ControllerProvider,
2517   $DateProvider,
2518   $DocumentProvider,
2519   $ExceptionHandlerProvider,
2520   $FilterProvider,
2521   $$ForceReflowProvider,
2522   $InterpolateProvider,
2523   $IntervalProvider,
2524   $$HashMapProvider,
2525   $HttpProvider,
2526   $HttpParamSerializerProvider,
2527   $HttpParamSerializerJQLikeProvider,
2528   $HttpBackendProvider,
2529   $xhrFactoryProvider,
2530   $jsonpCallbacksProvider,
2531   $LocationProvider,
2532   $LogProvider,
2533   $ParseProvider,
2534   $RootScopeProvider,
2535   $QProvider,
2536   $$QProvider,
2537   $$SanitizeUriProvider,
2538   $SceProvider,
2539   $SceDelegateProvider,
2540   $SnifferProvider,
2541   $TemplateCacheProvider,
2542   $TemplateRequestProvider,
2543   $$TestabilityProvider,
2544   $TimeoutProvider,
2545   $$RAFProvider,
2546   $WindowProvider,
2547   $$jqLiteProvider,
2548   $$CookieReaderProvider
2549 */
2550
2551
2552 /**
2553  * @ngdoc object
2554  * @name angular.version
2555  * @module ng
2556  * @description
2557  * An object that contains information about the current AngularJS version.
2558  *
2559  * This object has the following properties:
2560  *
2561  * - `full` â€“ `{string}` â€“ Full version string, such as "0.9.18".
2562  * - `major` â€“ `{number}` â€“ Major version number, such as "0".
2563  * - `minor` â€“ `{number}` â€“ Minor version number, such as "9".
2564  * - `dot` â€“ `{number}` â€“ Dot version number, such as "18".
2565  * - `codeName` â€“ `{string}` â€“ Code name of the release, such as "jiggling-armfat".
2566  */
2567 var version = {
2568   // These placeholder strings will be replaced by grunt's `build` task.
2569   // They need to be double- or single-quoted.
2570   full: '1.5.10',
2571   major: 1,
2572   minor: 5,
2573   dot: 10,
2574   codeName: 'asynchronous-synchronization'
2575 };
2576
2577
2578 function publishExternalAPI(angular) {
2579   extend(angular, {
2580     'bootstrap': bootstrap,
2581     'copy': copy,
2582     'extend': extend,
2583     'merge': merge,
2584     'equals': equals,
2585     'element': jqLite,
2586     'forEach': forEach,
2587     'injector': createInjector,
2588     'noop': noop,
2589     'bind': bind,
2590     'toJson': toJson,
2591     'fromJson': fromJson,
2592     'identity': identity,
2593     'isUndefined': isUndefined,
2594     'isDefined': isDefined,
2595     'isString': isString,
2596     'isFunction': isFunction,
2597     'isObject': isObject,
2598     'isNumber': isNumber,
2599     'isElement': isElement,
2600     'isArray': isArray,
2601     'version': version,
2602     'isDate': isDate,
2603     'lowercase': lowercase,
2604     'uppercase': uppercase,
2605     'callbacks': {$$counter: 0},
2606     'getTestability': getTestability,
2607     '$$minErr': minErr,
2608     '$$csp': csp,
2609     'reloadWithDebugInfo': reloadWithDebugInfo
2610   });
2611
2612   angularModule = setupModuleLoader(window);
2613
2614   angularModule('ng', ['ngLocale'], ['$provide',
2615     function ngModule($provide) {
2616       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2617       $provide.provider({
2618         $$sanitizeUri: $$SanitizeUriProvider
2619       });
2620       $provide.provider('$compile', $CompileProvider).
2621         directive({
2622             a: htmlAnchorDirective,
2623             input: inputDirective,
2624             textarea: inputDirective,
2625             form: formDirective,
2626             script: scriptDirective,
2627             select: selectDirective,
2628             option: optionDirective,
2629             ngBind: ngBindDirective,
2630             ngBindHtml: ngBindHtmlDirective,
2631             ngBindTemplate: ngBindTemplateDirective,
2632             ngClass: ngClassDirective,
2633             ngClassEven: ngClassEvenDirective,
2634             ngClassOdd: ngClassOddDirective,
2635             ngCloak: ngCloakDirective,
2636             ngController: ngControllerDirective,
2637             ngForm: ngFormDirective,
2638             ngHide: ngHideDirective,
2639             ngIf: ngIfDirective,
2640             ngInclude: ngIncludeDirective,
2641             ngInit: ngInitDirective,
2642             ngNonBindable: ngNonBindableDirective,
2643             ngPluralize: ngPluralizeDirective,
2644             ngRepeat: ngRepeatDirective,
2645             ngShow: ngShowDirective,
2646             ngStyle: ngStyleDirective,
2647             ngSwitch: ngSwitchDirective,
2648             ngSwitchWhen: ngSwitchWhenDirective,
2649             ngSwitchDefault: ngSwitchDefaultDirective,
2650             ngOptions: ngOptionsDirective,
2651             ngTransclude: ngTranscludeDirective,
2652             ngModel: ngModelDirective,
2653             ngList: ngListDirective,
2654             ngChange: ngChangeDirective,
2655             pattern: patternDirective,
2656             ngPattern: patternDirective,
2657             required: requiredDirective,
2658             ngRequired: requiredDirective,
2659             minlength: minlengthDirective,
2660             ngMinlength: minlengthDirective,
2661             maxlength: maxlengthDirective,
2662             ngMaxlength: maxlengthDirective,
2663             ngValue: ngValueDirective,
2664             ngModelOptions: ngModelOptionsDirective
2665         }).
2666         directive({
2667           ngInclude: ngIncludeFillContentDirective
2668         }).
2669         directive(ngAttributeAliasDirectives).
2670         directive(ngEventDirectives);
2671       $provide.provider({
2672         $anchorScroll: $AnchorScrollProvider,
2673         $animate: $AnimateProvider,
2674         $animateCss: $CoreAnimateCssProvider,
2675         $$animateJs: $$CoreAnimateJsProvider,
2676         $$animateQueue: $$CoreAnimateQueueProvider,
2677         $$AnimateRunner: $$AnimateRunnerFactoryProvider,
2678         $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
2679         $browser: $BrowserProvider,
2680         $cacheFactory: $CacheFactoryProvider,
2681         $controller: $ControllerProvider,
2682         $document: $DocumentProvider,
2683         $exceptionHandler: $ExceptionHandlerProvider,
2684         $filter: $FilterProvider,
2685         $$forceReflow: $$ForceReflowProvider,
2686         $interpolate: $InterpolateProvider,
2687         $interval: $IntervalProvider,
2688         $http: $HttpProvider,
2689         $httpParamSerializer: $HttpParamSerializerProvider,
2690         $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2691         $httpBackend: $HttpBackendProvider,
2692         $xhrFactory: $xhrFactoryProvider,
2693         $jsonpCallbacks: $jsonpCallbacksProvider,
2694         $location: $LocationProvider,
2695         $log: $LogProvider,
2696         $parse: $ParseProvider,
2697         $rootScope: $RootScopeProvider,
2698         $q: $QProvider,
2699         $$q: $$QProvider,
2700         $sce: $SceProvider,
2701         $sceDelegate: $SceDelegateProvider,
2702         $sniffer: $SnifferProvider,
2703         $templateCache: $TemplateCacheProvider,
2704         $templateRequest: $TemplateRequestProvider,
2705         $$testability: $$TestabilityProvider,
2706         $timeout: $TimeoutProvider,
2707         $window: $WindowProvider,
2708         $$rAF: $$RAFProvider,
2709         $$jqLite: $$jqLiteProvider,
2710         $$HashMap: $$HashMapProvider,
2711         $$cookieReader: $$CookieReaderProvider
2712       });
2713     }
2714   ]);
2715 }
2716
2717 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2718  *     Any commits to this file should be reviewed with security in mind.  *
2719  *   Changes to this file can potentially create security vulnerabilities. *
2720  *          An approval from 2 Core members with history of modifying      *
2721  *                         this file is required.                          *
2722  *                                                                         *
2723  *  Does the change somehow allow for arbitrary javascript to be executed? *
2724  *    Or allows for someone to change the prototype of built-in objects?   *
2725  *     Or gives undesired access to variables likes document or window?    *
2726  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2727
2728 /* global JQLitePrototype: true,
2729   addEventListenerFn: true,
2730   removeEventListenerFn: true,
2731   BOOLEAN_ATTR: true,
2732   ALIASED_ATTR: true
2733 */
2734
2735 //////////////////////////////////
2736 //JQLite
2737 //////////////////////////////////
2738
2739 /**
2740  * @ngdoc function
2741  * @name angular.element
2742  * @module ng
2743  * @kind function
2744  *
2745  * @description
2746  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2747  *
2748  * If jQuery is available, `angular.element` is an alias for the
2749  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2750  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
2751  *
2752  * jqLite is a tiny, API-compatible subset of jQuery that allows
2753  * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
2754  * commonly needed functionality with the goal of having a very small footprint.
2755  *
2756  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
2757  * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
2758  * specific version of jQuery if multiple versions exist on the page.
2759  *
2760  * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
2761  * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
2762  *
2763  * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
2764  * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
2765  * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
2766  *
2767  * ## Angular's jqLite
2768  * jqLite provides only the following jQuery methods:
2769  *
2770  * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
2771  * - [`after()`](http://api.jquery.com/after/)
2772  * - [`append()`](http://api.jquery.com/append/)
2773  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2774  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2775  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2776  * - [`clone()`](http://api.jquery.com/clone/)
2777  * - [`contents()`](http://api.jquery.com/contents/)
2778  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
2779  *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
2780  * - [`data()`](http://api.jquery.com/data/)
2781  * - [`detach()`](http://api.jquery.com/detach/)
2782  * - [`empty()`](http://api.jquery.com/empty/)
2783  * - [`eq()`](http://api.jquery.com/eq/)
2784  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2785  * - [`hasClass()`](http://api.jquery.com/hasClass/)
2786  * - [`html()`](http://api.jquery.com/html/)
2787  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2788  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2789  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2790  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2791  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2792  * - [`prepend()`](http://api.jquery.com/prepend/)
2793  * - [`prop()`](http://api.jquery.com/prop/)
2794  * - [`ready()`](http://api.jquery.com/ready/)
2795  * - [`remove()`](http://api.jquery.com/remove/)
2796  * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
2797  * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
2798  * - [`removeData()`](http://api.jquery.com/removeData/)
2799  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2800  * - [`text()`](http://api.jquery.com/text/)
2801  * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
2802  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
2803  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2804  * - [`val()`](http://api.jquery.com/val/)
2805  * - [`wrap()`](http://api.jquery.com/wrap/)
2806  *
2807  * ## jQuery/jqLite Extras
2808  * Angular also provides the following additional methods and events to both jQuery and jqLite:
2809  *
2810  * ### Events
2811  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2812  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2813  *    element before it is removed.
2814  *
2815  * ### Methods
2816  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2817  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2818  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2819  *   `'ngModel'`).
2820  * - `injector()` - retrieves the injector of the current element or its parent.
2821  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2822  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2823  *   be enabled.
2824  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2825  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2826  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2827  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2828  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2829  *   parent element is reached.
2830  *
2831  * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
2832  * https://github.com/angular/angular.js/issues/14251 for more information.
2833  *
2834  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2835  * @returns {Object} jQuery object.
2836  */
2837
2838 JQLite.expando = 'ng339';
2839
2840 var jqCache = JQLite.cache = {},
2841     jqId = 1,
2842     addEventListenerFn = function(element, type, fn) {
2843       element.addEventListener(type, fn, false);
2844     },
2845     removeEventListenerFn = function(element, type, fn) {
2846       element.removeEventListener(type, fn, false);
2847     };
2848
2849 /*
2850  * !!! This is an undocumented "private" function !!!
2851  */
2852 JQLite._data = function(node) {
2853   //jQuery always returns an object on cache miss
2854   return this.cache[node[this.expando]] || {};
2855 };
2856
2857 function jqNextId() { return ++jqId; }
2858
2859
2860 var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g;
2861 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2862 var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
2863 var jqLiteMinErr = minErr('jqLite');
2864
2865 /**
2866  * Converts snake_case to camelCase.
2867  * Also there is special case for Moz prefix starting with upper case letter.
2868  * @param name Name to normalize
2869  */
2870 function camelCase(name) {
2871   return name.
2872     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2873       return offset ? letter.toUpperCase() : letter;
2874     }).
2875     replace(MOZ_HACK_REGEXP, 'Moz$1');
2876 }
2877
2878 var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2879 var HTML_REGEXP = /<|&#?\w+;/;
2880 var TAG_NAME_REGEXP = /<([\w:-]+)/;
2881 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2882
2883 var wrapMap = {
2884   'option': [1, '<select multiple="multiple">', '</select>'],
2885
2886   'thead': [1, '<table>', '</table>'],
2887   'col': [2, '<table><colgroup>', '</colgroup></table>'],
2888   'tr': [2, '<table><tbody>', '</tbody></table>'],
2889   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2890   '_default': [0, '', '']
2891 };
2892
2893 wrapMap.optgroup = wrapMap.option;
2894 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2895 wrapMap.th = wrapMap.td;
2896
2897
2898 function jqLiteIsTextNode(html) {
2899   return !HTML_REGEXP.test(html);
2900 }
2901
2902 function jqLiteAcceptsData(node) {
2903   // The window object can accept data but has no nodeType
2904   // Otherwise we are only interested in elements (1) and documents (9)
2905   var nodeType = node.nodeType;
2906   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2907 }
2908
2909 function jqLiteHasData(node) {
2910   for (var key in jqCache[node.ng339]) {
2911     return true;
2912   }
2913   return false;
2914 }
2915
2916 function jqLiteCleanData(nodes) {
2917   for (var i = 0, ii = nodes.length; i < ii; i++) {
2918     jqLiteRemoveData(nodes[i]);
2919   }
2920 }
2921
2922 function jqLiteBuildFragment(html, context) {
2923   var tmp, tag, wrap,
2924       fragment = context.createDocumentFragment(),
2925       nodes = [], i;
2926
2927   if (jqLiteIsTextNode(html)) {
2928     // Convert non-html into a text node
2929     nodes.push(context.createTextNode(html));
2930   } else {
2931     // Convert html into DOM nodes
2932     tmp = fragment.appendChild(context.createElement('div'));
2933     tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
2934     wrap = wrapMap[tag] || wrapMap._default;
2935     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];
2936
2937     // Descend through wrappers to the right content
2938     i = wrap[0];
2939     while (i--) {
2940       tmp = tmp.lastChild;
2941     }
2942
2943     nodes = concat(nodes, tmp.childNodes);
2944
2945     tmp = fragment.firstChild;
2946     tmp.textContent = '';
2947   }
2948
2949   // Remove wrapper from fragment
2950   fragment.textContent = '';
2951   fragment.innerHTML = ''; // Clear inner HTML
2952   forEach(nodes, function(node) {
2953     fragment.appendChild(node);
2954   });
2955
2956   return fragment;
2957 }
2958
2959 function jqLiteParseHTML(html, context) {
2960   context = context || window.document;
2961   var parsed;
2962
2963   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2964     return [context.createElement(parsed[1])];
2965   }
2966
2967   if ((parsed = jqLiteBuildFragment(html, context))) {
2968     return parsed.childNodes;
2969   }
2970
2971   return [];
2972 }
2973
2974 function jqLiteWrapNode(node, wrapper) {
2975   var parent = node.parentNode;
2976
2977   if (parent) {
2978     parent.replaceChild(wrapper, node);
2979   }
2980
2981   wrapper.appendChild(node);
2982 }
2983
2984
2985 // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2986 var jqLiteContains = window.Node.prototype.contains || /** @this */ function(arg) {
2987   // eslint-disable-next-line no-bitwise
2988   return !!(this.compareDocumentPosition(arg) & 16);
2989 };
2990
2991 /////////////////////////////////////////////
2992 function JQLite(element) {
2993   if (element instanceof JQLite) {
2994     return element;
2995   }
2996
2997   var argIsString;
2998
2999   if (isString(element)) {
3000     element = trim(element);
3001     argIsString = true;
3002   }
3003   if (!(this instanceof JQLite)) {
3004     if (argIsString && element.charAt(0) !== '<') {
3005       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
3006     }
3007     return new JQLite(element);
3008   }
3009
3010   if (argIsString) {
3011     jqLiteAddNodes(this, jqLiteParseHTML(element));
3012   } else {
3013     jqLiteAddNodes(this, element);
3014   }
3015 }
3016
3017 function jqLiteClone(element) {
3018   return element.cloneNode(true);
3019 }
3020
3021 function jqLiteDealoc(element, onlyDescendants) {
3022   if (!onlyDescendants) jqLiteRemoveData(element);
3023
3024   if (element.querySelectorAll) {
3025     var descendants = element.querySelectorAll('*');
3026     for (var i = 0, l = descendants.length; i < l; i++) {
3027       jqLiteRemoveData(descendants[i]);
3028     }
3029   }
3030 }
3031
3032 function jqLiteOff(element, type, fn, unsupported) {
3033   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
3034
3035   var expandoStore = jqLiteExpandoStore(element);
3036   var events = expandoStore && expandoStore.events;
3037   var handle = expandoStore && expandoStore.handle;
3038
3039   if (!handle) return; //no listeners registered
3040
3041   if (!type) {
3042     for (type in events) {
3043       if (type !== '$destroy') {
3044         removeEventListenerFn(element, type, handle);
3045       }
3046       delete events[type];
3047     }
3048   } else {
3049
3050     var removeHandler = function(type) {
3051       var listenerFns = events[type];
3052       if (isDefined(fn)) {
3053         arrayRemove(listenerFns || [], fn);
3054       }
3055       if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
3056         removeEventListenerFn(element, type, handle);
3057         delete events[type];
3058       }
3059     };
3060
3061     forEach(type.split(' '), function(type) {
3062       removeHandler(type);
3063       if (MOUSE_EVENT_MAP[type]) {
3064         removeHandler(MOUSE_EVENT_MAP[type]);
3065       }
3066     });
3067   }
3068 }
3069
3070 function jqLiteRemoveData(element, name) {
3071   var expandoId = element.ng339;
3072   var expandoStore = expandoId && jqCache[expandoId];
3073
3074   if (expandoStore) {
3075     if (name) {
3076       delete expandoStore.data[name];
3077       return;
3078     }
3079
3080     if (expandoStore.handle) {
3081       if (expandoStore.events.$destroy) {
3082         expandoStore.handle({}, '$destroy');
3083       }
3084       jqLiteOff(element);
3085     }
3086     delete jqCache[expandoId];
3087     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
3088   }
3089 }
3090
3091
3092 function jqLiteExpandoStore(element, createIfNecessary) {
3093   var expandoId = element.ng339,
3094       expandoStore = expandoId && jqCache[expandoId];
3095
3096   if (createIfNecessary && !expandoStore) {
3097     element.ng339 = expandoId = jqNextId();
3098     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
3099   }
3100
3101   return expandoStore;
3102 }
3103
3104
3105 function jqLiteData(element, key, value) {
3106   if (jqLiteAcceptsData(element)) {
3107
3108     var isSimpleSetter = isDefined(value);
3109     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
3110     var massGetter = !key;
3111     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
3112     var data = expandoStore && expandoStore.data;
3113
3114     if (isSimpleSetter) { // data('key', value)
3115       data[key] = value;
3116     } else {
3117       if (massGetter) {  // data()
3118         return data;
3119       } else {
3120         if (isSimpleGetter) { // data('key')
3121           // don't force creation of expandoStore if it doesn't exist yet
3122           return data && data[key];
3123         } else { // mass-setter: data({key1: val1, key2: val2})
3124           extend(data, key);
3125         }
3126       }
3127     }
3128   }
3129 }
3130
3131 function jqLiteHasClass(element, selector) {
3132   if (!element.getAttribute) return false;
3133   return ((' ' + (element.getAttribute('class') || '') + ' ').replace(/[\n\t]/g, ' ').
3134       indexOf(' ' + selector + ' ') > -1);
3135 }
3136
3137 function jqLiteRemoveClass(element, cssClasses) {
3138   if (cssClasses && element.setAttribute) {
3139     forEach(cssClasses.split(' '), function(cssClass) {
3140       element.setAttribute('class', trim(
3141           (' ' + (element.getAttribute('class') || '') + ' ')
3142           .replace(/[\n\t]/g, ' ')
3143           .replace(' ' + trim(cssClass) + ' ', ' '))
3144       );
3145     });
3146   }
3147 }
3148
3149 function jqLiteAddClass(element, cssClasses) {
3150   if (cssClasses && element.setAttribute) {
3151     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3152                             .replace(/[\n\t]/g, ' ');
3153
3154     forEach(cssClasses.split(' '), function(cssClass) {
3155       cssClass = trim(cssClass);
3156       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
3157         existingClasses += cssClass + ' ';
3158       }
3159     });
3160
3161     element.setAttribute('class', trim(existingClasses));
3162   }
3163 }
3164
3165
3166 function jqLiteAddNodes(root, elements) {
3167   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3168
3169   if (elements) {
3170
3171     // if a Node (the most common case)
3172     if (elements.nodeType) {
3173       root[root.length++] = elements;
3174     } else {
3175       var length = elements.length;
3176
3177       // if an Array or NodeList and not a Window
3178       if (typeof length === 'number' && elements.window !== elements) {
3179         if (length) {
3180           for (var i = 0; i < length; i++) {
3181             root[root.length++] = elements[i];
3182           }
3183         }
3184       } else {
3185         root[root.length++] = elements;
3186       }
3187     }
3188   }
3189 }
3190
3191
3192 function jqLiteController(element, name) {
3193   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3194 }
3195
3196 function jqLiteInheritedData(element, name, value) {
3197   // if element is the document object work with the html element instead
3198   // this makes $(document).scope() possible
3199   if (element.nodeType === NODE_TYPE_DOCUMENT) {
3200     element = element.documentElement;
3201   }
3202   var names = isArray(name) ? name : [name];
3203
3204   while (element) {
3205     for (var i = 0, ii = names.length; i < ii; i++) {
3206       if (isDefined(value = jqLite.data(element, names[i]))) return value;
3207     }
3208
3209     // If dealing with a document fragment node with a host element, and no parent, use the host
3210     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3211     // to lookup parent controllers.
3212     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3213   }
3214 }
3215
3216 function jqLiteEmpty(element) {
3217   jqLiteDealoc(element, true);
3218   while (element.firstChild) {
3219     element.removeChild(element.firstChild);
3220   }
3221 }
3222
3223 function jqLiteRemove(element, keepData) {
3224   if (!keepData) jqLiteDealoc(element);
3225   var parent = element.parentNode;
3226   if (parent) parent.removeChild(element);
3227 }
3228
3229
3230 function jqLiteDocumentLoaded(action, win) {
3231   win = win || window;
3232   if (win.document.readyState === 'complete') {
3233     // Force the action to be run async for consistent behavior
3234     // from the action's point of view
3235     // i.e. it will definitely not be in a $apply
3236     win.setTimeout(action);
3237   } else {
3238     // No need to unbind this handler as load is only ever called once
3239     jqLite(win).on('load', action);
3240   }
3241 }
3242
3243 //////////////////////////////////////////
3244 // Functions which are declared directly.
3245 //////////////////////////////////////////
3246 var JQLitePrototype = JQLite.prototype = {
3247   ready: function(fn) {
3248     var fired = false;
3249
3250     function trigger() {
3251       if (fired) return;
3252       fired = true;
3253       fn();
3254     }
3255
3256     // check if document is already loaded
3257     if (window.document.readyState === 'complete') {
3258       window.setTimeout(trigger);
3259     } else {
3260       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3261       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3262       // eslint-disable-next-line new-cap
3263       JQLite(window).on('load', trigger); // fallback to window.onload for others
3264     }
3265   },
3266   toString: function() {
3267     var value = [];
3268     forEach(this, function(e) { value.push('' + e);});
3269     return '[' + value.join(', ') + ']';
3270   },
3271
3272   eq: function(index) {
3273       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3274   },
3275
3276   length: 0,
3277   push: push,
3278   sort: [].sort,
3279   splice: [].splice
3280 };
3281
3282 //////////////////////////////////////////
3283 // Functions iterating getter/setters.
3284 // these functions return self on setter and
3285 // value on get.
3286 //////////////////////////////////////////
3287 var BOOLEAN_ATTR = {};
3288 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3289   BOOLEAN_ATTR[lowercase(value)] = value;
3290 });
3291 var BOOLEAN_ELEMENTS = {};
3292 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3293   BOOLEAN_ELEMENTS[value] = true;
3294 });
3295 var ALIASED_ATTR = {
3296   'ngMinlength': 'minlength',
3297   'ngMaxlength': 'maxlength',
3298   'ngMin': 'min',
3299   'ngMax': 'max',
3300   'ngPattern': 'pattern'
3301 };
3302
3303 function getBooleanAttrName(element, name) {
3304   // check dom last since we will most likely fail on name
3305   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3306
3307   // booleanAttr is here twice to minimize DOM access
3308   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3309 }
3310
3311 function getAliasedAttrName(name) {
3312   return ALIASED_ATTR[name];
3313 }
3314
3315 forEach({
3316   data: jqLiteData,
3317   removeData: jqLiteRemoveData,
3318   hasData: jqLiteHasData,
3319   cleanData: jqLiteCleanData
3320 }, function(fn, name) {
3321   JQLite[name] = fn;
3322 });
3323
3324 forEach({
3325   data: jqLiteData,
3326   inheritedData: jqLiteInheritedData,
3327
3328   scope: function(element) {
3329     // Can't use jqLiteData here directly so we stay compatible with jQuery!
3330     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3331   },
3332
3333   isolateScope: function(element) {
3334     // Can't use jqLiteData here directly so we stay compatible with jQuery!
3335     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3336   },
3337
3338   controller: jqLiteController,
3339
3340   injector: function(element) {
3341     return jqLiteInheritedData(element, '$injector');
3342   },
3343
3344   removeAttr: function(element, name) {
3345     element.removeAttribute(name);
3346   },
3347
3348   hasClass: jqLiteHasClass,
3349
3350   css: function(element, name, value) {
3351     name = camelCase(name);
3352
3353     if (isDefined(value)) {
3354       element.style[name] = value;
3355     } else {
3356       return element.style[name];
3357     }
3358   },
3359
3360   attr: function(element, name, value) {
3361     var nodeType = element.nodeType;
3362     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3363       return;
3364     }
3365     var lowercasedName = lowercase(name);
3366     if (BOOLEAN_ATTR[lowercasedName]) {
3367       if (isDefined(value)) {
3368         if (value) {
3369           element[name] = true;
3370           element.setAttribute(name, lowercasedName);
3371         } else {
3372           element[name] = false;
3373           element.removeAttribute(lowercasedName);
3374         }
3375       } else {
3376         return (element[name] ||
3377                  (element.attributes.getNamedItem(name) || noop).specified)
3378                ? lowercasedName
3379                : undefined;
3380       }
3381     } else if (isDefined(value)) {
3382       element.setAttribute(name, value);
3383     } else if (element.getAttribute) {
3384       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3385       // some elements (e.g. Document) don't have get attribute, so return undefined
3386       var ret = element.getAttribute(name, 2);
3387       // normalize non-existing attributes to undefined (as jQuery)
3388       return ret === null ? undefined : ret;
3389     }
3390   },
3391
3392   prop: function(element, name, value) {
3393     if (isDefined(value)) {
3394       element[name] = value;
3395     } else {
3396       return element[name];
3397     }
3398   },
3399
3400   text: (function() {
3401     getText.$dv = '';
3402     return getText;
3403
3404     function getText(element, value) {
3405       if (isUndefined(value)) {
3406         var nodeType = element.nodeType;
3407         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3408       }
3409       element.textContent = value;
3410     }
3411   })(),
3412
3413   val: function(element, value) {
3414     if (isUndefined(value)) {
3415       if (element.multiple && nodeName_(element) === 'select') {
3416         var result = [];
3417         forEach(element.options, function(option) {
3418           if (option.selected) {
3419             result.push(option.value || option.text);
3420           }
3421         });
3422         return result.length === 0 ? null : result;
3423       }
3424       return element.value;
3425     }
3426     element.value = value;
3427   },
3428
3429   html: function(element, value) {
3430     if (isUndefined(value)) {
3431       return element.innerHTML;
3432     }
3433     jqLiteDealoc(element, true);
3434     element.innerHTML = value;
3435   },
3436
3437   empty: jqLiteEmpty
3438 }, function(fn, name) {
3439   /**
3440    * Properties: writes return selection, reads return first value
3441    */
3442   JQLite.prototype[name] = function(arg1, arg2) {
3443     var i, key;
3444     var nodeCount = this.length;
3445
3446     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3447     // in a way that survives minification.
3448     // jqLiteEmpty takes no arguments but is a setter.
3449     if (fn !== jqLiteEmpty &&
3450         (isUndefined((fn.length === 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3451       if (isObject(arg1)) {
3452
3453         // we are a write, but the object properties are the key/values
3454         for (i = 0; i < nodeCount; i++) {
3455           if (fn === jqLiteData) {
3456             // data() takes the whole object in jQuery
3457             fn(this[i], arg1);
3458           } else {
3459             for (key in arg1) {
3460               fn(this[i], key, arg1[key]);
3461             }
3462           }
3463         }
3464         // return self for chaining
3465         return this;
3466       } else {
3467         // we are a read, so read the first child.
3468         // TODO: do we still need this?
3469         var value = fn.$dv;
3470         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3471         var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3472         for (var j = 0; j < jj; j++) {
3473           var nodeValue = fn(this[j], arg1, arg2);
3474           value = value ? value + nodeValue : nodeValue;
3475         }
3476         return value;
3477       }
3478     } else {
3479       // we are a write, so apply to all children
3480       for (i = 0; i < nodeCount; i++) {
3481         fn(this[i], arg1, arg2);
3482       }
3483       // return self for chaining
3484       return this;
3485     }
3486   };
3487 });
3488
3489 function createEventHandler(element, events) {
3490   var eventHandler = function(event, type) {
3491     // jQuery specific api
3492     event.isDefaultPrevented = function() {
3493       return event.defaultPrevented;
3494     };
3495
3496     var eventFns = events[type || event.type];
3497     var eventFnsLength = eventFns ? eventFns.length : 0;
3498
3499     if (!eventFnsLength) return;
3500
3501     if (isUndefined(event.immediatePropagationStopped)) {
3502       var originalStopImmediatePropagation = event.stopImmediatePropagation;
3503       event.stopImmediatePropagation = function() {
3504         event.immediatePropagationStopped = true;
3505
3506         if (event.stopPropagation) {
3507           event.stopPropagation();
3508         }
3509
3510         if (originalStopImmediatePropagation) {
3511           originalStopImmediatePropagation.call(event);
3512         }
3513       };
3514     }
3515
3516     event.isImmediatePropagationStopped = function() {
3517       return event.immediatePropagationStopped === true;
3518     };
3519
3520     // Some events have special handlers that wrap the real handler
3521     var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3522
3523     // Copy event handlers in case event handlers array is modified during execution.
3524     if ((eventFnsLength > 1)) {
3525       eventFns = shallowCopy(eventFns);
3526     }
3527
3528     for (var i = 0; i < eventFnsLength; i++) {
3529       if (!event.isImmediatePropagationStopped()) {
3530         handlerWrapper(element, event, eventFns[i]);
3531       }
3532     }
3533   };
3534
3535   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3536   //       events on `element`
3537   eventHandler.elem = element;
3538   return eventHandler;
3539 }
3540
3541 function defaultHandlerWrapper(element, event, handler) {
3542   handler.call(element, event);
3543 }
3544
3545 function specialMouseHandlerWrapper(target, event, handler) {
3546   // Refer to jQuery's implementation of mouseenter & mouseleave
3547   // Read about mouseenter and mouseleave:
3548   // http://www.quirksmode.org/js/events_mouse.html#link8
3549   var related = event.relatedTarget;
3550   // For mousenter/leave call the handler if related is outside the target.
3551   // NB: No relatedTarget if the mouse left/entered the browser window
3552   if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3553     handler.call(target, event);
3554   }
3555 }
3556
3557 //////////////////////////////////////////
3558 // Functions iterating traversal.
3559 // These functions chain results into a single
3560 // selector.
3561 //////////////////////////////////////////
3562 forEach({
3563   removeData: jqLiteRemoveData,
3564
3565   on: function jqLiteOn(element, type, fn, unsupported) {
3566     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3567
3568     // Do not add event handlers to non-elements because they will not be cleaned up.
3569     if (!jqLiteAcceptsData(element)) {
3570       return;
3571     }
3572
3573     var expandoStore = jqLiteExpandoStore(element, true);
3574     var events = expandoStore.events;
3575     var handle = expandoStore.handle;
3576
3577     if (!handle) {
3578       handle = expandoStore.handle = createEventHandler(element, events);
3579     }
3580
3581     // http://jsperf.com/string-indexof-vs-split
3582     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3583     var i = types.length;
3584
3585     var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3586       var eventFns = events[type];
3587
3588       if (!eventFns) {
3589         eventFns = events[type] = [];
3590         eventFns.specialHandlerWrapper = specialHandlerWrapper;
3591         if (type !== '$destroy' && !noEventListener) {
3592           addEventListenerFn(element, type, handle);
3593         }
3594       }
3595
3596       eventFns.push(fn);
3597     };
3598
3599     while (i--) {
3600       type = types[i];
3601       if (MOUSE_EVENT_MAP[type]) {
3602         addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3603         addHandler(type, undefined, true);
3604       } else {
3605         addHandler(type);
3606       }
3607     }
3608   },
3609
3610   off: jqLiteOff,
3611
3612   one: function(element, type, fn) {
3613     element = jqLite(element);
3614
3615     //add the listener twice so that when it is called
3616     //you can remove the original function and still be
3617     //able to call element.off(ev, fn) normally
3618     element.on(type, function onFn() {
3619       element.off(type, fn);
3620       element.off(type, onFn);
3621     });
3622     element.on(type, fn);
3623   },
3624
3625   replaceWith: function(element, replaceNode) {
3626     var index, parent = element.parentNode;
3627     jqLiteDealoc(element);
3628     forEach(new JQLite(replaceNode), function(node) {
3629       if (index) {
3630         parent.insertBefore(node, index.nextSibling);
3631       } else {
3632         parent.replaceChild(node, element);
3633       }
3634       index = node;
3635     });
3636   },
3637
3638   children: function(element) {
3639     var children = [];
3640     forEach(element.childNodes, function(element) {
3641       if (element.nodeType === NODE_TYPE_ELEMENT) {
3642         children.push(element);
3643       }
3644     });
3645     return children;
3646   },
3647
3648   contents: function(element) {
3649     return element.contentDocument || element.childNodes || [];
3650   },
3651
3652   append: function(element, node) {
3653     var nodeType = element.nodeType;
3654     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3655
3656     node = new JQLite(node);
3657
3658     for (var i = 0, ii = node.length; i < ii; i++) {
3659       var child = node[i];
3660       element.appendChild(child);
3661     }
3662   },
3663
3664   prepend: function(element, node) {
3665     if (element.nodeType === NODE_TYPE_ELEMENT) {
3666       var index = element.firstChild;
3667       forEach(new JQLite(node), function(child) {
3668         element.insertBefore(child, index);
3669       });
3670     }
3671   },
3672
3673   wrap: function(element, wrapNode) {
3674     jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
3675   },
3676
3677   remove: jqLiteRemove,
3678
3679   detach: function(element) {
3680     jqLiteRemove(element, true);
3681   },
3682
3683   after: function(element, newElement) {
3684     var index = element, parent = element.parentNode;
3685
3686     if (parent) {
3687       newElement = new JQLite(newElement);
3688
3689       for (var i = 0, ii = newElement.length; i < ii; i++) {
3690         var node = newElement[i];
3691         parent.insertBefore(node, index.nextSibling);
3692         index = node;
3693       }
3694     }
3695   },
3696
3697   addClass: jqLiteAddClass,
3698   removeClass: jqLiteRemoveClass,
3699
3700   toggleClass: function(element, selector, condition) {
3701     if (selector) {
3702       forEach(selector.split(' '), function(className) {
3703         var classCondition = condition;
3704         if (isUndefined(classCondition)) {
3705           classCondition = !jqLiteHasClass(element, className);
3706         }
3707         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3708       });
3709     }
3710   },
3711
3712   parent: function(element) {
3713     var parent = element.parentNode;
3714     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3715   },
3716
3717   next: function(element) {
3718     return element.nextElementSibling;
3719   },
3720
3721   find: function(element, selector) {
3722     if (element.getElementsByTagName) {
3723       return element.getElementsByTagName(selector);
3724     } else {
3725       return [];
3726     }
3727   },
3728
3729   clone: jqLiteClone,
3730
3731   triggerHandler: function(element, event, extraParameters) {
3732
3733     var dummyEvent, eventFnsCopy, handlerArgs;
3734     var eventName = event.type || event;
3735     var expandoStore = jqLiteExpandoStore(element);
3736     var events = expandoStore && expandoStore.events;
3737     var eventFns = events && events[eventName];
3738
3739     if (eventFns) {
3740       // Create a dummy event to pass to the handlers
3741       dummyEvent = {
3742         preventDefault: function() { this.defaultPrevented = true; },
3743         isDefaultPrevented: function() { return this.defaultPrevented === true; },
3744         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3745         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3746         stopPropagation: noop,
3747         type: eventName,
3748         target: element
3749       };
3750
3751       // If a custom event was provided then extend our dummy event with it
3752       if (event.type) {
3753         dummyEvent = extend(dummyEvent, event);
3754       }
3755
3756       // Copy event handlers in case event handlers array is modified during execution.
3757       eventFnsCopy = shallowCopy(eventFns);
3758       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3759
3760       forEach(eventFnsCopy, function(fn) {
3761         if (!dummyEvent.isImmediatePropagationStopped()) {
3762           fn.apply(element, handlerArgs);
3763         }
3764       });
3765     }
3766   }
3767 }, function(fn, name) {
3768   /**
3769    * chaining functions
3770    */
3771   JQLite.prototype[name] = function(arg1, arg2, arg3) {
3772     var value;
3773
3774     for (var i = 0, ii = this.length; i < ii; i++) {
3775       if (isUndefined(value)) {
3776         value = fn(this[i], arg1, arg2, arg3);
3777         if (isDefined(value)) {
3778           // any function which returns a value needs to be wrapped
3779           value = jqLite(value);
3780         }
3781       } else {
3782         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3783       }
3784     }
3785     return isDefined(value) ? value : this;
3786   };
3787 });
3788
3789 // bind legacy bind/unbind to on/off
3790 JQLite.prototype.bind = JQLite.prototype.on;
3791 JQLite.prototype.unbind = JQLite.prototype.off;
3792
3793
3794 // Provider for private $$jqLite service
3795 /** @this */
3796 function $$jqLiteProvider() {
3797   this.$get = function $$jqLite() {
3798     return extend(JQLite, {
3799       hasClass: function(node, classes) {
3800         if (node.attr) node = node[0];
3801         return jqLiteHasClass(node, classes);
3802       },
3803       addClass: function(node, classes) {
3804         if (node.attr) node = node[0];
3805         return jqLiteAddClass(node, classes);
3806       },
3807       removeClass: function(node, classes) {
3808         if (node.attr) node = node[0];
3809         return jqLiteRemoveClass(node, classes);
3810       }
3811     });
3812   };
3813 }
3814
3815 /**
3816  * Computes a hash of an 'obj'.
3817  * Hash of a:
3818  *  string is string
3819  *  number is number as string
3820  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3821  *         that is also assigned to the $$hashKey property of the object.
3822  *
3823  * @param obj
3824  * @returns {string} hash string such that the same input will have the same hash string.
3825  *         The resulting string key is in 'type:hashKey' format.
3826  */
3827 function hashKey(obj, nextUidFn) {
3828   var key = obj && obj.$$hashKey;
3829
3830   if (key) {
3831     if (typeof key === 'function') {
3832       key = obj.$$hashKey();
3833     }
3834     return key;
3835   }
3836
3837   var objType = typeof obj;
3838   if (objType === 'function' || (objType === 'object' && obj !== null)) {
3839     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3840   } else {
3841     key = objType + ':' + obj;
3842   }
3843
3844   return key;
3845 }
3846
3847 /**
3848  * HashMap which can use objects as keys
3849  */
3850 function HashMap(array, isolatedUid) {
3851   if (isolatedUid) {
3852     var uid = 0;
3853     this.nextUid = function() {
3854       return ++uid;
3855     };
3856   }
3857   forEach(array, this.put, this);
3858 }
3859 HashMap.prototype = {
3860   /**
3861    * Store key value pair
3862    * @param key key to store can be any type
3863    * @param value value to store can be any type
3864    */
3865   put: function(key, value) {
3866     this[hashKey(key, this.nextUid)] = value;
3867   },
3868
3869   /**
3870    * @param key
3871    * @returns {Object} the value for the key
3872    */
3873   get: function(key) {
3874     return this[hashKey(key, this.nextUid)];
3875   },
3876
3877   /**
3878    * Remove the key/value pair
3879    * @param key
3880    */
3881   remove: function(key) {
3882     var value = this[key = hashKey(key, this.nextUid)];
3883     delete this[key];
3884     return value;
3885   }
3886 };
3887
3888 var $$HashMapProvider = [/** @this */function() {
3889   this.$get = [function() {
3890     return HashMap;
3891   }];
3892 }];
3893
3894 /**
3895  * @ngdoc function
3896  * @module ng
3897  * @name angular.injector
3898  * @kind function
3899  *
3900  * @description
3901  * Creates an injector object that can be used for retrieving services as well as for
3902  * dependency injection (see {@link guide/di dependency injection}).
3903  *
3904  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3905  *     {@link angular.module}. The `ng` module must be explicitly added.
3906  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3907  *     disallows argument name annotation inference.
3908  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3909  *
3910  * @example
3911  * Typical usage
3912  * ```js
3913  *   // create an injector
3914  *   var $injector = angular.injector(['ng']);
3915  *
3916  *   // use the injector to kick off your application
3917  *   // use the type inference to auto inject arguments, or use implicit injection
3918  *   $injector.invoke(function($rootScope, $compile, $document) {
3919  *     $compile($document)($rootScope);
3920  *     $rootScope.$digest();
3921  *   });
3922  * ```
3923  *
3924  * Sometimes you want to get access to the injector of a currently running Angular app
3925  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3926  * application has been bootstrapped. You can do this using the extra `injector()` added
3927  * to JQuery/jqLite elements. See {@link angular.element}.
3928  *
3929  * *This is fairly rare but could be the case if a third party library is injecting the
3930  * markup.*
3931  *
3932  * In the following example a new block of HTML containing a `ng-controller`
3933  * directive is added to the end of the document body by JQuery. We then compile and link
3934  * it into the current AngularJS scope.
3935  *
3936  * ```js
3937  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3938  * $(document.body).append($div);
3939  *
3940  * angular.element(document).injector().invoke(function($compile) {
3941  *   var scope = angular.element($div).scope();
3942  *   $compile($div)(scope);
3943  * });
3944  * ```
3945  */
3946
3947
3948 /**
3949  * @ngdoc module
3950  * @name auto
3951  * @installation
3952  * @description
3953  *
3954  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3955  */
3956
3957 var ARROW_ARG = /^([^(]+?)=>/;
3958 var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m;
3959 var FN_ARG_SPLIT = /,/;
3960 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3961 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3962 var $injectorMinErr = minErr('$injector');
3963
3964 function stringifyFn(fn) {
3965   // Support: Chrome 50-51 only
3966   // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
3967   // (See https://github.com/angular/angular.js/issues/14487.)
3968   // TODO (gkalpak): Remove workaround when Chrome v52 is released
3969   return Function.prototype.toString.call(fn) + ' ';
3970 }
3971
3972 function extractArgs(fn) {
3973   var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
3974       args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
3975   return args;
3976 }
3977
3978 function anonFn(fn) {
3979   // For anonymous functions, showing at the very least the function signature can help in
3980   // debugging.
3981   var args = extractArgs(fn);
3982   if (args) {
3983     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3984   }
3985   return 'fn';
3986 }
3987
3988 function annotate(fn, strictDi, name) {
3989   var $inject,
3990       argDecl,
3991       last;
3992
3993   if (typeof fn === 'function') {
3994     if (!($inject = fn.$inject)) {
3995       $inject = [];
3996       if (fn.length) {
3997         if (strictDi) {
3998           if (!isString(name) || !name) {
3999             name = fn.name || anonFn(fn);
4000           }
4001           throw $injectorMinErr('strictdi',
4002             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
4003         }
4004         argDecl = extractArgs(fn);
4005         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
4006           arg.replace(FN_ARG, function(all, underscore, name) {
4007             $inject.push(name);
4008           });
4009         });
4010       }
4011       fn.$inject = $inject;
4012     }
4013   } else if (isArray(fn)) {
4014     last = fn.length - 1;
4015     assertArgFn(fn[last], 'fn');
4016     $inject = fn.slice(0, last);
4017   } else {
4018     assertArgFn(fn, 'fn', true);
4019   }
4020   return $inject;
4021 }
4022
4023 ///////////////////////////////////////
4024
4025 /**
4026  * @ngdoc service
4027  * @name $injector
4028  *
4029  * @description
4030  *
4031  * `$injector` is used to retrieve object instances as defined by
4032  * {@link auto.$provide provider}, instantiate types, invoke methods,
4033  * and load modules.
4034  *
4035  * The following always holds true:
4036  *
4037  * ```js
4038  *   var $injector = angular.injector();
4039  *   expect($injector.get('$injector')).toBe($injector);
4040  *   expect($injector.invoke(function($injector) {
4041  *     return $injector;
4042  *   })).toBe($injector);
4043  * ```
4044  *
4045  * # Injection Function Annotation
4046  *
4047  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
4048  * following are all valid ways of annotating function with injection arguments and are equivalent.
4049  *
4050  * ```js
4051  *   // inferred (only works if code not minified/obfuscated)
4052  *   $injector.invoke(function(serviceA){});
4053  *
4054  *   // annotated
4055  *   function explicit(serviceA) {};
4056  *   explicit.$inject = ['serviceA'];
4057  *   $injector.invoke(explicit);
4058  *
4059  *   // inline
4060  *   $injector.invoke(['serviceA', function(serviceA){}]);
4061  * ```
4062  *
4063  * ## Inference
4064  *
4065  * In JavaScript calling `toString()` on a function returns the function definition. The definition
4066  * can then be parsed and the function arguments can be extracted. This method of discovering
4067  * annotations is disallowed when the injector is in strict mode.
4068  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
4069  * argument names.
4070  *
4071  * ## `$inject` Annotation
4072  * By adding an `$inject` property onto a function the injection parameters can be specified.
4073  *
4074  * ## Inline
4075  * As an array of injection names, where the last item in the array is the function to call.
4076  */
4077
4078 /**
4079  * @ngdoc method
4080  * @name $injector#get
4081  *
4082  * @description
4083  * Return an instance of the service.
4084  *
4085  * @param {string} name The name of the instance to retrieve.
4086  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
4087  * @return {*} The instance.
4088  */
4089
4090 /**
4091  * @ngdoc method
4092  * @name $injector#invoke
4093  *
4094  * @description
4095  * Invoke the method and supply the method arguments from the `$injector`.
4096  *
4097  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
4098  *   injected according to the {@link guide/di $inject Annotation} rules.
4099  * @param {Object=} self The `this` for the invoked method.
4100  * @param {Object=} locals Optional object. If preset then any argument names are read from this
4101  *                         object first, before the `$injector` is consulted.
4102  * @returns {*} the value returned by the invoked `fn` function.
4103  */
4104
4105 /**
4106  * @ngdoc method
4107  * @name $injector#has
4108  *
4109  * @description
4110  * Allows the user to query if the particular service exists.
4111  *
4112  * @param {string} name Name of the service to query.
4113  * @returns {boolean} `true` if injector has given service.
4114  */
4115
4116 /**
4117  * @ngdoc method
4118  * @name $injector#instantiate
4119  * @description
4120  * Create a new instance of JS type. The method takes a constructor function, invokes the new
4121  * operator, and supplies all of the arguments to the constructor function as specified by the
4122  * constructor annotation.
4123  *
4124  * @param {Function} Type Annotated constructor function.
4125  * @param {Object=} locals Optional object. If preset then any argument names are read from this
4126  * object first, before the `$injector` is consulted.
4127  * @returns {Object} new instance of `Type`.
4128  */
4129
4130 /**
4131  * @ngdoc method
4132  * @name $injector#annotate
4133  *
4134  * @description
4135  * Returns an array of service names which the function is requesting for injection. This API is
4136  * used by the injector to determine which services need to be injected into the function when the
4137  * function is invoked. There are three ways in which the function can be annotated with the needed
4138  * dependencies.
4139  *
4140  * # Argument names
4141  *
4142  * The simplest form is to extract the dependencies from the arguments of the function. This is done
4143  * by converting the function into a string using `toString()` method and extracting the argument
4144  * names.
4145  * ```js
4146  *   // Given
4147  *   function MyController($scope, $route) {
4148  *     // ...
4149  *   }
4150  *
4151  *   // Then
4152  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4153  * ```
4154  *
4155  * You can disallow this method by using strict injection mode.
4156  *
4157  * This method does not work with code minification / obfuscation. For this reason the following
4158  * annotation strategies are supported.
4159  *
4160  * # The `$inject` property
4161  *
4162  * If a function has an `$inject` property and its value is an array of strings, then the strings
4163  * represent names of services to be injected into the function.
4164  * ```js
4165  *   // Given
4166  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
4167  *     // ...
4168  *   }
4169  *   // Define function dependencies
4170  *   MyController['$inject'] = ['$scope', '$route'];
4171  *
4172  *   // Then
4173  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4174  * ```
4175  *
4176  * # The array notation
4177  *
4178  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4179  * is very inconvenient. In these situations using the array notation to specify the dependencies in
4180  * a way that survives minification is a better choice:
4181  *
4182  * ```js
4183  *   // We wish to write this (not minification / obfuscation safe)
4184  *   injector.invoke(function($compile, $rootScope) {
4185  *     // ...
4186  *   });
4187  *
4188  *   // We are forced to write break inlining
4189  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4190  *     // ...
4191  *   };
4192  *   tmpFn.$inject = ['$compile', '$rootScope'];
4193  *   injector.invoke(tmpFn);
4194  *
4195  *   // To better support inline function the inline annotation is supported
4196  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4197  *     // ...
4198  *   }]);
4199  *
4200  *   // Therefore
4201  *   expect(injector.annotate(
4202  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4203  *    ).toEqual(['$compile', '$rootScope']);
4204  * ```
4205  *
4206  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4207  * be retrieved as described above.
4208  *
4209  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4210  *
4211  * @returns {Array.<string>} The names of the services which the function requires.
4212  */
4213
4214
4215
4216 /**
4217  * @ngdoc service
4218  * @name $provide
4219  *
4220  * @description
4221  *
4222  * The {@link auto.$provide $provide} service has a number of methods for registering components
4223  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4224  * {@link angular.Module}.
4225  *
4226  * An Angular **service** is a singleton object created by a **service factory**.  These **service
4227  * factories** are functions which, in turn, are created by a **service provider**.
4228  * The **service providers** are constructor functions. When instantiated they must contain a
4229  * property called `$get`, which holds the **service factory** function.
4230  *
4231  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4232  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4233  * function to get the instance of the **service**.
4234  *
4235  * Often services have no configuration options and there is no need to add methods to the service
4236  * provider.  The provider will be no more than a constructor function with a `$get` property. For
4237  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4238  * services without specifying a provider.
4239  *
4240  * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
4241  *     {@link auto.$injector $injector}
4242  * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
4243  *     providers and services.
4244  * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
4245  *     services, not providers.
4246  * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
4247  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4248  *     given factory function.
4249  * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
4250  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4251  *      a new object using the given constructor function.
4252  * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
4253  *      will be able to modify or replace the implementation of another service.
4254  *
4255  * See the individual methods for more information and examples.
4256  */
4257
4258 /**
4259  * @ngdoc method
4260  * @name $provide#provider
4261  * @description
4262  *
4263  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4264  * are constructor functions, whose instances are responsible for "providing" a factory for a
4265  * service.
4266  *
4267  * Service provider names start with the name of the service they provide followed by `Provider`.
4268  * For example, the {@link ng.$log $log} service has a provider called
4269  * {@link ng.$logProvider $logProvider}.
4270  *
4271  * Service provider objects can have additional methods which allow configuration of the provider
4272  * and its service. Importantly, you can configure what kind of service is created by the `$get`
4273  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4274  * method {@link ng.$logProvider#debugEnabled debugEnabled}
4275  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4276  * console or not.
4277  *
4278  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4279                         'Provider'` key.
4280  * @param {(Object|function())} provider If the provider is:
4281  *
4282  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4283  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4284  *   - `Constructor`: a new instance of the provider will be created using
4285  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4286  *
4287  * @returns {Object} registered provider instance
4288
4289  * @example
4290  *
4291  * The following example shows how to create a simple event tracking service and register it using
4292  * {@link auto.$provide#provider $provide.provider()}.
4293  *
4294  * ```js
4295  *  // Define the eventTracker provider
4296  *  function EventTrackerProvider() {
4297  *    var trackingUrl = '/track';
4298  *
4299  *    // A provider method for configuring where the tracked events should been saved
4300  *    this.setTrackingUrl = function(url) {
4301  *      trackingUrl = url;
4302  *    };
4303  *
4304  *    // The service factory function
4305  *    this.$get = ['$http', function($http) {
4306  *      var trackedEvents = {};
4307  *      return {
4308  *        // Call this to track an event
4309  *        event: function(event) {
4310  *          var count = trackedEvents[event] || 0;
4311  *          count += 1;
4312  *          trackedEvents[event] = count;
4313  *          return count;
4314  *        },
4315  *        // Call this to save the tracked events to the trackingUrl
4316  *        save: function() {
4317  *          $http.post(trackingUrl, trackedEvents);
4318  *        }
4319  *      };
4320  *    }];
4321  *  }
4322  *
4323  *  describe('eventTracker', function() {
4324  *    var postSpy;
4325  *
4326  *    beforeEach(module(function($provide) {
4327  *      // Register the eventTracker provider
4328  *      $provide.provider('eventTracker', EventTrackerProvider);
4329  *    }));
4330  *
4331  *    beforeEach(module(function(eventTrackerProvider) {
4332  *      // Configure eventTracker provider
4333  *      eventTrackerProvider.setTrackingUrl('/custom-track');
4334  *    }));
4335  *
4336  *    it('tracks events', inject(function(eventTracker) {
4337  *      expect(eventTracker.event('login')).toEqual(1);
4338  *      expect(eventTracker.event('login')).toEqual(2);
4339  *    }));
4340  *
4341  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4342  *      postSpy = spyOn($http, 'post');
4343  *      eventTracker.event('login');
4344  *      eventTracker.save();
4345  *      expect(postSpy).toHaveBeenCalled();
4346  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4347  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4348  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4349  *    }));
4350  *  });
4351  * ```
4352  */
4353
4354 /**
4355  * @ngdoc method
4356  * @name $provide#factory
4357  * @description
4358  *
4359  * Register a **service factory**, which will be called to return the service instance.
4360  * This is short for registering a service where its provider consists of only a `$get` property,
4361  * which is the given service factory function.
4362  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4363  * configure your service in a provider.
4364  *
4365  * @param {string} name The name of the instance.
4366  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4367  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4368  * @returns {Object} registered provider instance
4369  *
4370  * @example
4371  * Here is an example of registering a service
4372  * ```js
4373  *   $provide.factory('ping', ['$http', function($http) {
4374  *     return function ping() {
4375  *       return $http.send('/ping');
4376  *     };
4377  *   }]);
4378  * ```
4379  * You would then inject and use this service like this:
4380  * ```js
4381  *   someModule.controller('Ctrl', ['ping', function(ping) {
4382  *     ping();
4383  *   }]);
4384  * ```
4385  */
4386
4387
4388 /**
4389  * @ngdoc method
4390  * @name $provide#service
4391  * @description
4392  *
4393  * Register a **service constructor**, which will be invoked with `new` to create the service
4394  * instance.
4395  * This is short for registering a service where its provider's `$get` property is a factory
4396  * function that returns an instance instantiated by the injector from the service constructor
4397  * function.
4398  *
4399  * Internally it looks a bit like this:
4400  *
4401  * ```
4402  * {
4403  *   $get: function() {
4404  *     return $injector.instantiate(constructor);
4405  *   }
4406  * }
4407  * ```
4408  *
4409  *
4410  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4411  * as a type/class.
4412  *
4413  * @param {string} name The name of the instance.
4414  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4415  *     that will be instantiated.
4416  * @returns {Object} registered provider instance
4417  *
4418  * @example
4419  * Here is an example of registering a service using
4420  * {@link auto.$provide#service $provide.service(class)}.
4421  * ```js
4422  *   var Ping = function($http) {
4423  *     this.$http = $http;
4424  *   };
4425  *
4426  *   Ping.$inject = ['$http'];
4427  *
4428  *   Ping.prototype.send = function() {
4429  *     return this.$http.get('/ping');
4430  *   };
4431  *   $provide.service('ping', Ping);
4432  * ```
4433  * You would then inject and use this service like this:
4434  * ```js
4435  *   someModule.controller('Ctrl', ['ping', function(ping) {
4436  *     ping.send();
4437  *   }]);
4438  * ```
4439  */
4440
4441
4442 /**
4443  * @ngdoc method
4444  * @name $provide#value
4445  * @description
4446  *
4447  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4448  * number, an array, an object or a function. This is short for registering a service where its
4449  * provider's `$get` property is a factory function that takes no arguments and returns the **value
4450  * service**. That also means it is not possible to inject other services into a value service.
4451  *
4452  * Value services are similar to constant services, except that they cannot be injected into a
4453  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4454  * an Angular {@link auto.$provide#decorator decorator}.
4455  *
4456  * @param {string} name The name of the instance.
4457  * @param {*} value The value.
4458  * @returns {Object} registered provider instance
4459  *
4460  * @example
4461  * Here are some examples of creating value services.
4462  * ```js
4463  *   $provide.value('ADMIN_USER', 'admin');
4464  *
4465  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4466  *
4467  *   $provide.value('halfOf', function(value) {
4468  *     return value / 2;
4469  *   });
4470  * ```
4471  */
4472
4473
4474 /**
4475  * @ngdoc method
4476  * @name $provide#constant
4477  * @description
4478  *
4479  * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
4480  * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
4481  * possible to inject other services into a constant.
4482  *
4483  * But unlike {@link auto.$provide#value value}, a constant can be
4484  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4485  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4486  *
4487  * @param {string} name The name of the constant.
4488  * @param {*} value The constant value.
4489  * @returns {Object} registered instance
4490  *
4491  * @example
4492  * Here a some examples of creating constants:
4493  * ```js
4494  *   $provide.constant('SHARD_HEIGHT', 306);
4495  *
4496  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4497  *
4498  *   $provide.constant('double', function(value) {
4499  *     return value * 2;
4500  *   });
4501  * ```
4502  */
4503
4504
4505 /**
4506  * @ngdoc method
4507  * @name $provide#decorator
4508  * @description
4509  *
4510  * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
4511  * intercepts the creation of a service, allowing it to override or modify the behavior of the
4512  * service. The return value of the decorator function may be the original service, or a new service
4513  * that replaces (or wraps and delegates to) the original service.
4514  *
4515  * You can find out more about using decorators in the {@link guide/decorators} guide.
4516  *
4517  * @param {string} name The name of the service to decorate.
4518  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4519  *    provided and should return the decorated service instance. The function is called using
4520  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4521  *    Local injection arguments:
4522  *
4523  *    * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
4524  *      decorated or delegated to.
4525  *
4526  * @example
4527  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4528  * calls to {@link ng.$log#error $log.warn()}.
4529  * ```js
4530  *   $provide.decorator('$log', ['$delegate', function($delegate) {
4531  *     $delegate.warn = $delegate.error;
4532  *     return $delegate;
4533  *   }]);
4534  * ```
4535  */
4536
4537
4538 function createInjector(modulesToLoad, strictDi) {
4539   strictDi = (strictDi === true);
4540   var INSTANTIATING = {},
4541       providerSuffix = 'Provider',
4542       path = [],
4543       loadedModules = new HashMap([], true),
4544       providerCache = {
4545         $provide: {
4546             provider: supportObject(provider),
4547             factory: supportObject(factory),
4548             service: supportObject(service),
4549             value: supportObject(value),
4550             constant: supportObject(constant),
4551             decorator: decorator
4552           }
4553       },
4554       providerInjector = (providerCache.$injector =
4555           createInternalInjector(providerCache, function(serviceName, caller) {
4556             if (angular.isString(caller)) {
4557               path.push(caller);
4558             }
4559             throw $injectorMinErr('unpr', 'Unknown provider: {0}', path.join(' <- '));
4560           })),
4561       instanceCache = {},
4562       protoInstanceInjector =
4563           createInternalInjector(instanceCache, function(serviceName, caller) {
4564             var provider = providerInjector.get(serviceName + providerSuffix, caller);
4565             return instanceInjector.invoke(
4566                 provider.$get, provider, undefined, serviceName);
4567           }),
4568       instanceInjector = protoInstanceInjector;
4569
4570   providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
4571   var runBlocks = loadModules(modulesToLoad);
4572   instanceInjector = protoInstanceInjector.get('$injector');
4573   instanceInjector.strictDi = strictDi;
4574   forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
4575
4576   return instanceInjector;
4577
4578   ////////////////////////////////////
4579   // $provider
4580   ////////////////////////////////////
4581
4582   function supportObject(delegate) {
4583     return function(key, value) {
4584       if (isObject(key)) {
4585         forEach(key, reverseParams(delegate));
4586       } else {
4587         return delegate(key, value);
4588       }
4589     };
4590   }
4591
4592   function provider(name, provider_) {
4593     assertNotHasOwnProperty(name, 'service');
4594     if (isFunction(provider_) || isArray(provider_)) {
4595       provider_ = providerInjector.instantiate(provider_);
4596     }
4597     if (!provider_.$get) {
4598       throw $injectorMinErr('pget', 'Provider \'{0}\' must define $get factory method.', name);
4599     }
4600     return (providerCache[name + providerSuffix] = provider_);
4601   }
4602
4603   function enforceReturnValue(name, factory) {
4604     return /** @this */ function enforcedReturnValue() {
4605       var result = instanceInjector.invoke(factory, this);
4606       if (isUndefined(result)) {
4607         throw $injectorMinErr('undef', 'Provider \'{0}\' must return a value from $get factory method.', name);
4608       }
4609       return result;
4610     };
4611   }
4612
4613   function factory(name, factoryFn, enforce) {
4614     return provider(name, {
4615       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4616     });
4617   }
4618
4619   function service(name, constructor) {
4620     return factory(name, ['$injector', function($injector) {
4621       return $injector.instantiate(constructor);
4622     }]);
4623   }
4624
4625   function value(name, val) { return factory(name, valueFn(val), false); }
4626
4627   function constant(name, value) {
4628     assertNotHasOwnProperty(name, 'constant');
4629     providerCache[name] = value;
4630     instanceCache[name] = value;
4631   }
4632
4633   function decorator(serviceName, decorFn) {
4634     var origProvider = providerInjector.get(serviceName + providerSuffix),
4635         orig$get = origProvider.$get;
4636
4637     origProvider.$get = function() {
4638       var origInstance = instanceInjector.invoke(orig$get, origProvider);
4639       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4640     };
4641   }
4642
4643   ////////////////////////////////////
4644   // Module Loading
4645   ////////////////////////////////////
4646   function loadModules(modulesToLoad) {
4647     assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4648     var runBlocks = [], moduleFn;
4649     forEach(modulesToLoad, function(module) {
4650       if (loadedModules.get(module)) return;
4651       loadedModules.put(module, true);
4652
4653       function runInvokeQueue(queue) {
4654         var i, ii;
4655         for (i = 0, ii = queue.length; i < ii; i++) {
4656           var invokeArgs = queue[i],
4657               provider = providerInjector.get(invokeArgs[0]);
4658
4659           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4660         }
4661       }
4662
4663       try {
4664         if (isString(module)) {
4665           moduleFn = angularModule(module);
4666           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4667           runInvokeQueue(moduleFn._invokeQueue);
4668           runInvokeQueue(moduleFn._configBlocks);
4669         } else if (isFunction(module)) {
4670             runBlocks.push(providerInjector.invoke(module));
4671         } else if (isArray(module)) {
4672             runBlocks.push(providerInjector.invoke(module));
4673         } else {
4674           assertArgFn(module, 'module');
4675         }
4676       } catch (e) {
4677         if (isArray(module)) {
4678           module = module[module.length - 1];
4679         }
4680         if (e.message && e.stack && e.stack.indexOf(e.message) === -1) {
4681           // Safari & FF's stack traces don't contain error.message content
4682           // unlike those of Chrome and IE
4683           // So if stack doesn't contain message, we create a new string that contains both.
4684           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4685           // eslint-disable-next-line no-ex-assign
4686           e = e.message + '\n' + e.stack;
4687         }
4688         throw $injectorMinErr('modulerr', 'Failed to instantiate module {0} due to:\n{1}',
4689                   module, e.stack || e.message || e);
4690       }
4691     });
4692     return runBlocks;
4693   }
4694
4695   ////////////////////////////////////
4696   // internal Injector
4697   ////////////////////////////////////
4698
4699   function createInternalInjector(cache, factory) {
4700
4701     function getService(serviceName, caller) {
4702       if (cache.hasOwnProperty(serviceName)) {
4703         if (cache[serviceName] === INSTANTIATING) {
4704           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4705                     serviceName + ' <- ' + path.join(' <- '));
4706         }
4707         return cache[serviceName];
4708       } else {
4709         try {
4710           path.unshift(serviceName);
4711           cache[serviceName] = INSTANTIATING;
4712           cache[serviceName] = factory(serviceName, caller);
4713           return cache[serviceName];
4714         } catch (err) {
4715           if (cache[serviceName] === INSTANTIATING) {
4716             delete cache[serviceName];
4717           }
4718           throw err;
4719         } finally {
4720           path.shift();
4721         }
4722       }
4723     }
4724
4725
4726     function injectionArgs(fn, locals, serviceName) {
4727       var args = [],
4728           $inject = createInjector.$$annotate(fn, strictDi, serviceName);
4729
4730       for (var i = 0, length = $inject.length; i < length; i++) {
4731         var key = $inject[i];
4732         if (typeof key !== 'string') {
4733           throw $injectorMinErr('itkn',
4734                   'Incorrect injection token! Expected service name as string, got {0}', key);
4735         }
4736         args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
4737                                                          getService(key, serviceName));
4738       }
4739       return args;
4740     }
4741
4742     function isClass(func) {
4743       // IE 9-11 do not support classes and IE9 leaks with the code below.
4744       if (msie <= 11) {
4745         return false;
4746       }
4747       // Support: Edge 12-13 only
4748       // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
4749       return typeof func === 'function'
4750         && /^(?:class\b|constructor\()/.test(stringifyFn(func));
4751     }
4752
4753     function invoke(fn, self, locals, serviceName) {
4754       if (typeof locals === 'string') {
4755         serviceName = locals;
4756         locals = null;
4757       }
4758
4759       var args = injectionArgs(fn, locals, serviceName);
4760       if (isArray(fn)) {
4761         fn = fn[fn.length - 1];
4762       }
4763
4764       if (!isClass(fn)) {
4765         // http://jsperf.com/angularjs-invoke-apply-vs-switch
4766         // #5388
4767         return fn.apply(self, args);
4768       } else {
4769         args.unshift(null);
4770         return new (Function.prototype.bind.apply(fn, args))();
4771       }
4772     }
4773
4774
4775     function instantiate(Type, locals, serviceName) {
4776       // Check if Type is annotated and use just the given function at n-1 as parameter
4777       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4778       var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
4779       var args = injectionArgs(Type, locals, serviceName);
4780       // Empty object at position 0 is ignored for invocation with `new`, but required.
4781       args.unshift(null);
4782       return new (Function.prototype.bind.apply(ctor, args))();
4783     }
4784
4785
4786     return {
4787       invoke: invoke,
4788       instantiate: instantiate,
4789       get: getService,
4790       annotate: createInjector.$$annotate,
4791       has: function(name) {
4792         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4793       }
4794     };
4795   }
4796 }
4797
4798 createInjector.$$annotate = annotate;
4799
4800 /**
4801  * @ngdoc provider
4802  * @name $anchorScrollProvider
4803  * @this
4804  *
4805  * @description
4806  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4807  * {@link ng.$location#hash $location.hash()} changes.
4808  */
4809 function $AnchorScrollProvider() {
4810
4811   var autoScrollingEnabled = true;
4812
4813   /**
4814    * @ngdoc method
4815    * @name $anchorScrollProvider#disableAutoScrolling
4816    *
4817    * @description
4818    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4819    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4820    * Use this method to disable automatic scrolling.
4821    *
4822    * If automatic scrolling is disabled, one must explicitly call
4823    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4824    * current hash.
4825    */
4826   this.disableAutoScrolling = function() {
4827     autoScrollingEnabled = false;
4828   };
4829
4830   /**
4831    * @ngdoc service
4832    * @name $anchorScroll
4833    * @kind function
4834    * @requires $window
4835    * @requires $location
4836    * @requires $rootScope
4837    *
4838    * @description
4839    * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4840    * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4841    * in the
4842    * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
4843    *
4844    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4845    * match any anchor whenever it changes. This can be disabled by calling
4846    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4847    *
4848    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4849    * vertical scroll-offset (either fixed or dynamic).
4850    *
4851    * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4852    *                       {@link ng.$location#hash $location.hash()} will be used.
4853    *
4854    * @property {(number|function|jqLite)} yOffset
4855    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4856    * positioned elements at the top of the page, such as navbars, headers etc.
4857    *
4858    * `yOffset` can be specified in various ways:
4859    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4860    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4861    *   a number representing the offset (in pixels).<br /><br />
4862    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4863    *   the top of the page to the element's bottom will be used as offset.<br />
4864    *   **Note**: The element will be taken into account only as long as its `position` is set to
4865    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4866    *   their height and/or positioning according to the viewport's size.
4867    *
4868    * <br />
4869    * <div class="alert alert-warning">
4870    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4871    * not some child element.
4872    * </div>
4873    *
4874    * @example
4875      <example module="anchorScrollExample" name="anchor-scroll">
4876        <file name="index.html">
4877          <div id="scrollArea" ng-controller="ScrollController">
4878            <a ng-click="gotoBottom()">Go to bottom</a>
4879            <a id="bottom"></a> You're at the bottom!
4880          </div>
4881        </file>
4882        <file name="script.js">
4883          angular.module('anchorScrollExample', [])
4884            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4885              function($scope, $location, $anchorScroll) {
4886                $scope.gotoBottom = function() {
4887                  // set the location.hash to the id of
4888                  // the element you wish to scroll to.
4889                  $location.hash('bottom');
4890
4891                  // call $anchorScroll()
4892                  $anchorScroll();
4893                };
4894              }]);
4895        </file>
4896        <file name="style.css">
4897          #scrollArea {
4898            height: 280px;
4899            overflow: auto;
4900          }
4901
4902          #bottom {
4903            display: block;
4904            margin-top: 2000px;
4905          }
4906        </file>
4907      </example>
4908    *
4909    * <hr />
4910    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4911    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4912    *
4913    * @example
4914      <example module="anchorScrollOffsetExample" name="anchor-scroll-offset">
4915        <file name="index.html">
4916          <div class="fixed-header" ng-controller="headerCtrl">
4917            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4918              Go to anchor {{x}}
4919            </a>
4920          </div>
4921          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4922            Anchor {{x}} of 5
4923          </div>
4924        </file>
4925        <file name="script.js">
4926          angular.module('anchorScrollOffsetExample', [])
4927            .run(['$anchorScroll', function($anchorScroll) {
4928              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4929            }])
4930            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4931              function($anchorScroll, $location, $scope) {
4932                $scope.gotoAnchor = function(x) {
4933                  var newHash = 'anchor' + x;
4934                  if ($location.hash() !== newHash) {
4935                    // set the $location.hash to `newHash` and
4936                    // $anchorScroll will automatically scroll to it
4937                    $location.hash('anchor' + x);
4938                  } else {
4939                    // call $anchorScroll() explicitly,
4940                    // since $location.hash hasn't changed
4941                    $anchorScroll();
4942                  }
4943                };
4944              }
4945            ]);
4946        </file>
4947        <file name="style.css">
4948          body {
4949            padding-top: 50px;
4950          }
4951
4952          .anchor {
4953            border: 2px dashed DarkOrchid;
4954            padding: 10px 10px 200px 10px;
4955          }
4956
4957          .fixed-header {
4958            background-color: rgba(0, 0, 0, 0.2);
4959            height: 50px;
4960            position: fixed;
4961            top: 0; left: 0; right: 0;
4962          }
4963
4964          .fixed-header > a {
4965            display: inline-block;
4966            margin: 5px 15px;
4967          }
4968        </file>
4969      </example>
4970    */
4971   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4972     var document = $window.document;
4973
4974     // Helper function to get first anchor from a NodeList
4975     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4976     //  and working in all supported browsers.)
4977     function getFirstAnchor(list) {
4978       var result = null;
4979       Array.prototype.some.call(list, function(element) {
4980         if (nodeName_(element) === 'a') {
4981           result = element;
4982           return true;
4983         }
4984       });
4985       return result;
4986     }
4987
4988     function getYOffset() {
4989
4990       var offset = scroll.yOffset;
4991
4992       if (isFunction(offset)) {
4993         offset = offset();
4994       } else if (isElement(offset)) {
4995         var elem = offset[0];
4996         var style = $window.getComputedStyle(elem);
4997         if (style.position !== 'fixed') {
4998           offset = 0;
4999         } else {
5000           offset = elem.getBoundingClientRect().bottom;
5001         }
5002       } else if (!isNumber(offset)) {
5003         offset = 0;
5004       }
5005
5006       return offset;
5007     }
5008
5009     function scrollTo(elem) {
5010       if (elem) {
5011         elem.scrollIntoView();
5012
5013         var offset = getYOffset();
5014
5015         if (offset) {
5016           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
5017           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
5018           // top of the viewport.
5019           //
5020           // IF the number of pixels from the top of `elem` to the end of the page's content is less
5021           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
5022           // way down the page.
5023           //
5024           // This is often the case for elements near the bottom of the page.
5025           //
5026           // In such cases we do not need to scroll the whole `offset` up, just the difference between
5027           // the top of the element and the offset, which is enough to align the top of `elem` at the
5028           // desired position.
5029           var elemTop = elem.getBoundingClientRect().top;
5030           $window.scrollBy(0, elemTop - offset);
5031         }
5032       } else {
5033         $window.scrollTo(0, 0);
5034       }
5035     }
5036
5037     function scroll(hash) {
5038       // Allow numeric hashes
5039       hash = isString(hash) ? hash : isNumber(hash) ? hash.toString() : $location.hash();
5040       var elm;
5041
5042       // empty hash, scroll to the top of the page
5043       if (!hash) scrollTo(null);
5044
5045       // element with given id
5046       else if ((elm = document.getElementById(hash))) scrollTo(elm);
5047
5048       // first anchor with given name :-D
5049       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
5050
5051       // no element and hash === 'top', scroll to the top of the page
5052       else if (hash === 'top') scrollTo(null);
5053     }
5054
5055     // does not scroll when user clicks on anchor link that is currently on
5056     // (no url change, no $location.hash() change), browser native does scroll
5057     if (autoScrollingEnabled) {
5058       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
5059         function autoScrollWatchAction(newVal, oldVal) {
5060           // skip the initial scroll if $location.hash is empty
5061           if (newVal === oldVal && newVal === '') return;
5062
5063           jqLiteDocumentLoaded(function() {
5064             $rootScope.$evalAsync(scroll);
5065           });
5066         });
5067     }
5068
5069     return scroll;
5070   }];
5071 }
5072
5073 var $animateMinErr = minErr('$animate');
5074 var ELEMENT_NODE = 1;
5075 var NG_ANIMATE_CLASSNAME = 'ng-animate';
5076
5077 function mergeClasses(a,b) {
5078   if (!a && !b) return '';
5079   if (!a) return b;
5080   if (!b) return a;
5081   if (isArray(a)) a = a.join(' ');
5082   if (isArray(b)) b = b.join(' ');
5083   return a + ' ' + b;
5084 }
5085
5086 function extractElementNode(element) {
5087   for (var i = 0; i < element.length; i++) {
5088     var elm = element[i];
5089     if (elm.nodeType === ELEMENT_NODE) {
5090       return elm;
5091     }
5092   }
5093 }
5094
5095 function splitClasses(classes) {
5096   if (isString(classes)) {
5097     classes = classes.split(' ');
5098   }
5099
5100   // Use createMap() to prevent class assumptions involving property names in
5101   // Object.prototype
5102   var obj = createMap();
5103   forEach(classes, function(klass) {
5104     // sometimes the split leaves empty string values
5105     // incase extra spaces were applied to the options
5106     if (klass.length) {
5107       obj[klass] = true;
5108     }
5109   });
5110   return obj;
5111 }
5112
5113 // if any other type of options value besides an Object value is
5114 // passed into the $animate.method() animation then this helper code
5115 // will be run which will ignore it. While this patch is not the
5116 // greatest solution to this, a lot of existing plugins depend on
5117 // $animate to either call the callback (< 1.2) or return a promise
5118 // that can be changed. This helper function ensures that the options
5119 // are wiped clean incase a callback function is provided.
5120 function prepareAnimateOptions(options) {
5121   return isObject(options)
5122       ? options
5123       : {};
5124 }
5125
5126 var $$CoreAnimateJsProvider = /** @this */ function() {
5127   this.$get = noop;
5128 };
5129
5130 // this is prefixed with Core since it conflicts with
5131 // the animateQueueProvider defined in ngAnimate/animateQueue.js
5132 var $$CoreAnimateQueueProvider = /** @this */ function() {
5133   var postDigestQueue = new HashMap();
5134   var postDigestElements = [];
5135
5136   this.$get = ['$$AnimateRunner', '$rootScope',
5137        function($$AnimateRunner,   $rootScope) {
5138     return {
5139       enabled: noop,
5140       on: noop,
5141       off: noop,
5142       pin: noop,
5143
5144       push: function(element, event, options, domOperation) {
5145         if (domOperation) {
5146           domOperation();
5147         }
5148
5149         options = options || {};
5150         if (options.from) {
5151           element.css(options.from);
5152         }
5153         if (options.to) {
5154           element.css(options.to);
5155         }
5156
5157         if (options.addClass || options.removeClass) {
5158           addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
5159         }
5160
5161         var runner = new $$AnimateRunner();
5162
5163         // since there are no animations to run the runner needs to be
5164         // notified that the animation call is complete.
5165         runner.complete();
5166         return runner;
5167       }
5168     };
5169
5170
5171     function updateData(data, classes, value) {
5172       var changed = false;
5173       if (classes) {
5174         classes = isString(classes) ? classes.split(' ') :
5175                   isArray(classes) ? classes : [];
5176         forEach(classes, function(className) {
5177           if (className) {
5178             changed = true;
5179             data[className] = value;
5180           }
5181         });
5182       }
5183       return changed;
5184     }
5185
5186     function handleCSSClassChanges() {
5187       forEach(postDigestElements, function(element) {
5188         var data = postDigestQueue.get(element);
5189         if (data) {
5190           var existing = splitClasses(element.attr('class'));
5191           var toAdd = '';
5192           var toRemove = '';
5193           forEach(data, function(status, className) {
5194             var hasClass = !!existing[className];
5195             if (status !== hasClass) {
5196               if (status) {
5197                 toAdd += (toAdd.length ? ' ' : '') + className;
5198               } else {
5199                 toRemove += (toRemove.length ? ' ' : '') + className;
5200               }
5201             }
5202           });
5203
5204           forEach(element, function(elm) {
5205             if (toAdd) {
5206               jqLiteAddClass(elm, toAdd);
5207             }
5208             if (toRemove) {
5209               jqLiteRemoveClass(elm, toRemove);
5210             }
5211           });
5212           postDigestQueue.remove(element);
5213         }
5214       });
5215       postDigestElements.length = 0;
5216     }
5217
5218
5219     function addRemoveClassesPostDigest(element, add, remove) {
5220       var data = postDigestQueue.get(element) || {};
5221
5222       var classesAdded = updateData(data, add, true);
5223       var classesRemoved = updateData(data, remove, false);
5224
5225       if (classesAdded || classesRemoved) {
5226
5227         postDigestQueue.put(element, data);
5228         postDigestElements.push(element);
5229
5230         if (postDigestElements.length === 1) {
5231           $rootScope.$$postDigest(handleCSSClassChanges);
5232         }
5233       }
5234     }
5235   }];
5236 };
5237
5238 /**
5239  * @ngdoc provider
5240  * @name $animateProvider
5241  *
5242  * @description
5243  * Default implementation of $animate that doesn't perform any animations, instead just
5244  * synchronously performs DOM updates and resolves the returned runner promise.
5245  *
5246  * In order to enable animations the `ngAnimate` module has to be loaded.
5247  *
5248  * To see the functional implementation check out `src/ngAnimate/animate.js`.
5249  */
5250 var $AnimateProvider = ['$provide', /** @this */ function($provide) {
5251   var provider = this;
5252
5253   this.$$registeredAnimations = Object.create(null);
5254
5255    /**
5256    * @ngdoc method
5257    * @name $animateProvider#register
5258    *
5259    * @description
5260    * Registers a new injectable animation factory function. The factory function produces the
5261    * animation object which contains callback functions for each event that is expected to be
5262    * animated.
5263    *
5264    *   * `eventFn`: `function(element, ... , doneFunction, options)`
5265    *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5266    *   on the type of animation additional arguments will be injected into the animation function. The
5267    *   list below explains the function signatures for the different animation methods:
5268    *
5269    *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5270    *   - addClass: function(element, addedClasses, doneFunction, options)
5271    *   - removeClass: function(element, removedClasses, doneFunction, options)
5272    *   - enter, leave, move: function(element, doneFunction, options)
5273    *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5274    *
5275    *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5276    *
5277    * ```js
5278    *   return {
5279    *     //enter, leave, move signature
5280    *     eventFn : function(element, done, options) {
5281    *       //code to run the animation
5282    *       //once complete, then run done()
5283    *       return function endFunction(wasCancelled) {
5284    *         //code to cancel the animation
5285    *       }
5286    *     }
5287    *   }
5288    * ```
5289    *
5290    * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5291    * @param {Function} factory The factory function that will be executed to return the animation
5292    *                           object.
5293    */
5294   this.register = function(name, factory) {
5295     if (name && name.charAt(0) !== '.') {
5296       throw $animateMinErr('notcsel', 'Expecting class selector starting with \'.\' got \'{0}\'.', name);
5297     }
5298
5299     var key = name + '-animation';
5300     provider.$$registeredAnimations[name.substr(1)] = key;
5301     $provide.factory(key, factory);
5302   };
5303
5304   /**
5305    * @ngdoc method
5306    * @name $animateProvider#classNameFilter
5307    *
5308    * @description
5309    * Sets and/or returns the CSS class regular expression that is checked when performing
5310    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5311    * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5312    * When setting the `classNameFilter` value, animations will only be performed on elements
5313    * that successfully match the filter expression. This in turn can boost performance
5314    * for low-powered devices as well as applications containing a lot of structural operations.
5315    * @param {RegExp=} expression The className expression which will be checked against all animations
5316    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5317    */
5318   this.classNameFilter = function(expression) {
5319     if (arguments.length === 1) {
5320       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
5321       if (this.$$classNameFilter) {
5322         var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
5323         if (reservedRegex.test(this.$$classNameFilter.toString())) {
5324           throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5325
5326         }
5327       }
5328     }
5329     return this.$$classNameFilter;
5330   };
5331
5332   this.$get = ['$$animateQueue', function($$animateQueue) {
5333     function domInsert(element, parentElement, afterElement) {
5334       // if for some reason the previous element was removed
5335       // from the dom sometime before this code runs then let's
5336       // just stick to using the parent element as the anchor
5337       if (afterElement) {
5338         var afterNode = extractElementNode(afterElement);
5339         if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5340           afterElement = null;
5341         }
5342       }
5343       if (afterElement) {
5344         afterElement.after(element);
5345       } else {
5346         parentElement.prepend(element);
5347       }
5348     }
5349
5350     /**
5351      * @ngdoc service
5352      * @name $animate
5353      * @description The $animate service exposes a series of DOM utility methods that provide support
5354      * for animation hooks. The default behavior is the application of DOM operations, however,
5355      * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5356      * to ensure that animation runs with the triggered DOM operation.
5357      *
5358      * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5359      * included and only when it is active then the animation hooks that `$animate` triggers will be
5360      * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5361      * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5362      * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5363      *
5364      * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5365      *
5366      * To learn more about enabling animation support, click here to visit the
5367      * {@link ngAnimate ngAnimate module page}.
5368      */
5369     return {
5370       // we don't call it directly since non-existant arguments may
5371       // be interpreted as null within the sub enabled function
5372
5373       /**
5374        *
5375        * @ngdoc method
5376        * @name $animate#on
5377        * @kind function
5378        * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5379        *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5380        *    is fired with the following params:
5381        *
5382        * ```js
5383        * $animate.on('enter', container,
5384        *    function callback(element, phase) {
5385        *      // cool we detected an enter animation within the container
5386        *    }
5387        * );
5388        * ```
5389        *
5390        * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5391        * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5392        *     as well as among its children
5393        * @param {Function} callback the callback function that will be fired when the listener is triggered
5394        *
5395        * The arguments present in the callback function are:
5396        * * `element` - The captured DOM element that the animation was fired on.
5397        * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5398        */
5399       on: $$animateQueue.on,
5400
5401       /**
5402        *
5403        * @ngdoc method
5404        * @name $animate#off
5405        * @kind function
5406        * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5407        * can be used in three different ways depending on the arguments:
5408        *
5409        * ```js
5410        * // remove all the animation event listeners listening for `enter`
5411        * $animate.off('enter');
5412        *
5413        * // remove listeners for all animation events from the container element
5414        * $animate.off(container);
5415        *
5416        * // remove all the animation event listeners listening for `enter` on the given element and its children
5417        * $animate.off('enter', container);
5418        *
5419        * // remove the event listener function provided by `callback` that is set
5420        * // to listen for `enter` on the given `container` as well as its children
5421        * $animate.off('enter', container, callback);
5422        * ```
5423        *
5424        * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
5425        * addClass, removeClass, etc...), or the container element. If it is the element, all other
5426        * arguments are ignored.
5427        * @param {DOMElement=} container the container element the event listener was placed on
5428        * @param {Function=} callback the callback function that was registered as the listener
5429        */
5430       off: $$animateQueue.off,
5431
5432       /**
5433        * @ngdoc method
5434        * @name $animate#pin
5435        * @kind function
5436        * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5437        *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5438        *    element despite being outside the realm of the application or within another application. Say for example if the application
5439        *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5440        *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5441        *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5442        *
5443        *    Note that this feature is only active when the `ngAnimate` module is used.
5444        *
5445        * @param {DOMElement} element the external element that will be pinned
5446        * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5447        */
5448       pin: $$animateQueue.pin,
5449
5450       /**
5451        *
5452        * @ngdoc method
5453        * @name $animate#enabled
5454        * @kind function
5455        * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5456        * function can be called in four ways:
5457        *
5458        * ```js
5459        * // returns true or false
5460        * $animate.enabled();
5461        *
5462        * // changes the enabled state for all animations
5463        * $animate.enabled(false);
5464        * $animate.enabled(true);
5465        *
5466        * // returns true or false if animations are enabled for an element
5467        * $animate.enabled(element);
5468        *
5469        * // changes the enabled state for an element and its children
5470        * $animate.enabled(element, true);
5471        * $animate.enabled(element, false);
5472        * ```
5473        *
5474        * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5475        * @param {boolean=} enabled whether or not the animations will be enabled for the element
5476        *
5477        * @return {boolean} whether or not animations are enabled
5478        */
5479       enabled: $$animateQueue.enabled,
5480
5481       /**
5482        * @ngdoc method
5483        * @name $animate#cancel
5484        * @kind function
5485        * @description Cancels the provided animation.
5486        *
5487        * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5488        */
5489       cancel: function(runner) {
5490         if (runner.end) {
5491           runner.end();
5492         }
5493       },
5494
5495       /**
5496        *
5497        * @ngdoc method
5498        * @name $animate#enter
5499        * @kind function
5500        * @description Inserts the element into the DOM either after the `after` element (if provided) or
5501        *   as the first child within the `parent` element and then triggers an animation.
5502        *   A promise is returned that will be resolved during the next digest once the animation
5503        *   has completed.
5504        *
5505        * @param {DOMElement} element the element which will be inserted into the DOM
5506        * @param {DOMElement} parent the parent element which will append the element as
5507        *   a child (so long as the after element is not present)
5508        * @param {DOMElement=} after the sibling element after which the element will be appended
5509        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5510        *   The object can have the following properties:
5511        *
5512        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5513        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5514        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5515        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5516        *
5517        * @return {Promise} the animation callback promise
5518        */
5519       enter: function(element, parent, after, options) {
5520         parent = parent && jqLite(parent);
5521         after = after && jqLite(after);
5522         parent = parent || after.parent();
5523         domInsert(element, parent, after);
5524         return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5525       },
5526
5527       /**
5528        *
5529        * @ngdoc method
5530        * @name $animate#move
5531        * @kind function
5532        * @description Inserts (moves) the element into its new position in the DOM either after
5533        *   the `after` element (if provided) or as the first child within the `parent` element
5534        *   and then triggers an animation. A promise is returned that will be resolved
5535        *   during the next digest once the animation has completed.
5536        *
5537        * @param {DOMElement} element the element which will be moved into the new DOM position
5538        * @param {DOMElement} parent the parent element which will append the element as
5539        *   a child (so long as the after element is not present)
5540        * @param {DOMElement=} after the sibling element after which the element will be appended
5541        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5542        *   The object can have the following properties:
5543        *
5544        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5545        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5546        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5547        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5548        *
5549        * @return {Promise} the animation callback promise
5550        */
5551       move: function(element, parent, after, options) {
5552         parent = parent && jqLite(parent);
5553         after = after && jqLite(after);
5554         parent = parent || after.parent();
5555         domInsert(element, parent, after);
5556         return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5557       },
5558
5559       /**
5560        * @ngdoc method
5561        * @name $animate#leave
5562        * @kind function
5563        * @description Triggers an animation and then removes the element from the DOM.
5564        * When the function is called a promise is returned that will be resolved during the next
5565        * digest once the animation has completed.
5566        *
5567        * @param {DOMElement} element the element which will be removed from the DOM
5568        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5569        *   The object can have the following properties:
5570        *
5571        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5572        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5573        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5574        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5575        *
5576        * @return {Promise} the animation callback promise
5577        */
5578       leave: function(element, options) {
5579         return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5580           element.remove();
5581         });
5582       },
5583
5584       /**
5585        * @ngdoc method
5586        * @name $animate#addClass
5587        * @kind function
5588        *
5589        * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5590        *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5591        *   animation if element already contains the CSS class or if the class is removed at a later step.
5592        *   Note that class-based animations are treated differently compared to structural animations
5593        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5594        *   depending if CSS or JavaScript animations are used.
5595        *
5596        * @param {DOMElement} element the element which the CSS classes will be applied to
5597        * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5598        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5599        *   The object can have the following properties:
5600        *
5601        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5602        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5603        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5604        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5605        *
5606        * @return {Promise} the animation callback promise
5607        */
5608       addClass: function(element, className, options) {
5609         options = prepareAnimateOptions(options);
5610         options.addClass = mergeClasses(options.addclass, className);
5611         return $$animateQueue.push(element, 'addClass', options);
5612       },
5613
5614       /**
5615        * @ngdoc method
5616        * @name $animate#removeClass
5617        * @kind function
5618        *
5619        * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5620        *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5621        *   animation if element does not contain the CSS class or if the class is added at a later step.
5622        *   Note that class-based animations are treated differently compared to structural animations
5623        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5624        *   depending if CSS or JavaScript animations are used.
5625        *
5626        * @param {DOMElement} element the element which the CSS classes will be applied to
5627        * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5628        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5629        *   The object can have the following properties:
5630        *
5631        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5632        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5633        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5634        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5635        *
5636        * @return {Promise} the animation callback promise
5637        */
5638       removeClass: function(element, className, options) {
5639         options = prepareAnimateOptions(options);
5640         options.removeClass = mergeClasses(options.removeClass, className);
5641         return $$animateQueue.push(element, 'removeClass', options);
5642       },
5643
5644       /**
5645        * @ngdoc method
5646        * @name $animate#setClass
5647        * @kind function
5648        *
5649        * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5650        *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5651        *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5652        *    passed. Note that class-based animations are treated differently compared to structural animations
5653        *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5654        *    depending if CSS or JavaScript animations are used.
5655        *
5656        * @param {DOMElement} element the element which the CSS classes will be applied to
5657        * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5658        * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5659        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5660        *   The object can have the following properties:
5661        *
5662        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5663        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5664        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5665        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5666        *
5667        * @return {Promise} the animation callback promise
5668        */
5669       setClass: function(element, add, remove, options) {
5670         options = prepareAnimateOptions(options);
5671         options.addClass = mergeClasses(options.addClass, add);
5672         options.removeClass = mergeClasses(options.removeClass, remove);
5673         return $$animateQueue.push(element, 'setClass', options);
5674       },
5675
5676       /**
5677        * @ngdoc method
5678        * @name $animate#animate
5679        * @kind function
5680        *
5681        * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5682        * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
5683        * on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and
5684        * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
5685        * style in `to`, the style in `from` is applied immediately, and no animation is run.
5686        * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
5687        * method (or as part of the `options` parameter):
5688        *
5689        * ```js
5690        * ngModule.animation('.my-inline-animation', function() {
5691        *   return {
5692        *     animate : function(element, from, to, done, options) {
5693        *       //animation
5694        *       done();
5695        *     }
5696        *   }
5697        * });
5698        * ```
5699        *
5700        * @param {DOMElement} element the element which the CSS styles will be applied to
5701        * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5702        * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5703        * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5704        *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5705        *    (Note that if no animation is detected then this value will not be applied to the element.)
5706        * @param {object=} options an optional collection of options/styles that will be applied to the element.
5707        *   The object can have the following properties:
5708        *
5709        *   - **addClass** - `{string}` - space-separated CSS classes to add to element
5710        *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
5711        *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
5712        *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
5713        *
5714        * @return {Promise} the animation callback promise
5715        */
5716       animate: function(element, from, to, className, options) {
5717         options = prepareAnimateOptions(options);
5718         options.from = options.from ? extend(options.from, from) : from;
5719         options.to   = options.to   ? extend(options.to, to)     : to;
5720
5721         className = className || 'ng-inline-animate';
5722         options.tempClasses = mergeClasses(options.tempClasses, className);
5723         return $$animateQueue.push(element, 'animate', options);
5724       }
5725     };
5726   }];
5727 }];
5728
5729 var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
5730   this.$get = ['$$rAF', function($$rAF) {
5731     var waitQueue = [];
5732
5733     function waitForTick(fn) {
5734       waitQueue.push(fn);
5735       if (waitQueue.length > 1) return;
5736       $$rAF(function() {
5737         for (var i = 0; i < waitQueue.length; i++) {
5738           waitQueue[i]();
5739         }
5740         waitQueue = [];
5741       });
5742     }
5743
5744     return function() {
5745       var passed = false;
5746       waitForTick(function() {
5747         passed = true;
5748       });
5749       return function(callback) {
5750         if (passed) {
5751           callback();
5752         } else {
5753           waitForTick(callback);
5754         }
5755       };
5756     };
5757   }];
5758 };
5759
5760 var $$AnimateRunnerFactoryProvider = /** @this */ function() {
5761   this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
5762        function($q,   $sniffer,   $$animateAsyncRun,   $document,   $timeout) {
5763
5764     var INITIAL_STATE = 0;
5765     var DONE_PENDING_STATE = 1;
5766     var DONE_COMPLETE_STATE = 2;
5767
5768     AnimateRunner.chain = function(chain, callback) {
5769       var index = 0;
5770
5771       next();
5772       function next() {
5773         if (index === chain.length) {
5774           callback(true);
5775           return;
5776         }
5777
5778         chain[index](function(response) {
5779           if (response === false) {
5780             callback(false);
5781             return;
5782           }
5783           index++;
5784           next();
5785         });
5786       }
5787     };
5788
5789     AnimateRunner.all = function(runners, callback) {
5790       var count = 0;
5791       var status = true;
5792       forEach(runners, function(runner) {
5793         runner.done(onProgress);
5794       });
5795
5796       function onProgress(response) {
5797         status = status && response;
5798         if (++count === runners.length) {
5799           callback(status);
5800         }
5801       }
5802     };
5803
5804     function AnimateRunner(host) {
5805       this.setHost(host);
5806
5807       var rafTick = $$animateAsyncRun();
5808       var timeoutTick = function(fn) {
5809         $timeout(fn, 0, false);
5810       };
5811
5812       this._doneCallbacks = [];
5813       this._tick = function(fn) {
5814         var doc = $document[0];
5815
5816         // the document may not be ready or attached
5817         // to the module for some internal tests
5818         if (doc && doc.hidden) {
5819           timeoutTick(fn);
5820         } else {
5821           rafTick(fn);
5822         }
5823       };
5824       this._state = 0;
5825     }
5826
5827     AnimateRunner.prototype = {
5828       setHost: function(host) {
5829         this.host = host || {};
5830       },
5831
5832       done: function(fn) {
5833         if (this._state === DONE_COMPLETE_STATE) {
5834           fn();
5835         } else {
5836           this._doneCallbacks.push(fn);
5837         }
5838       },
5839
5840       progress: noop,
5841
5842       getPromise: function() {
5843         if (!this.promise) {
5844           var self = this;
5845           this.promise = $q(function(resolve, reject) {
5846             self.done(function(status) {
5847               if (status === false) {
5848                 reject();
5849               } else {
5850                 resolve();
5851               }
5852             });
5853           });
5854         }
5855         return this.promise;
5856       },
5857
5858       then: function(resolveHandler, rejectHandler) {
5859         return this.getPromise().then(resolveHandler, rejectHandler);
5860       },
5861
5862       'catch': function(handler) {
5863         return this.getPromise()['catch'](handler);
5864       },
5865
5866       'finally': function(handler) {
5867         return this.getPromise()['finally'](handler);
5868       },
5869
5870       pause: function() {
5871         if (this.host.pause) {
5872           this.host.pause();
5873         }
5874       },
5875
5876       resume: function() {
5877         if (this.host.resume) {
5878           this.host.resume();
5879         }
5880       },
5881
5882       end: function() {
5883         if (this.host.end) {
5884           this.host.end();
5885         }
5886         this._resolve(true);
5887       },
5888
5889       cancel: function() {
5890         if (this.host.cancel) {
5891           this.host.cancel();
5892         }
5893         this._resolve(false);
5894       },
5895
5896       complete: function(response) {
5897         var self = this;
5898         if (self._state === INITIAL_STATE) {
5899           self._state = DONE_PENDING_STATE;
5900           self._tick(function() {
5901             self._resolve(response);
5902           });
5903         }
5904       },
5905
5906       _resolve: function(response) {
5907         if (this._state !== DONE_COMPLETE_STATE) {
5908           forEach(this._doneCallbacks, function(fn) {
5909             fn(response);
5910           });
5911           this._doneCallbacks.length = 0;
5912           this._state = DONE_COMPLETE_STATE;
5913         }
5914       }
5915     };
5916
5917     return AnimateRunner;
5918   }];
5919 };
5920
5921 /* exported $CoreAnimateCssProvider */
5922
5923 /**
5924  * @ngdoc service
5925  * @name $animateCss
5926  * @kind object
5927  * @this
5928  *
5929  * @description
5930  * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
5931  * then the `$animateCss` service will actually perform animations.
5932  *
5933  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5934  */
5935 var $CoreAnimateCssProvider = function() {
5936   this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
5937
5938     return function(element, initialOptions) {
5939       // all of the animation functions should create
5940       // a copy of the options data, however, if a
5941       // parent service has already created a copy then
5942       // we should stick to using that
5943       var options = initialOptions || {};
5944       if (!options.$$prepared) {
5945         options = copy(options);
5946       }
5947
5948       // there is no point in applying the styles since
5949       // there is no animation that goes on at all in
5950       // this version of $animateCss.
5951       if (options.cleanupStyles) {
5952         options.from = options.to = null;
5953       }
5954
5955       if (options.from) {
5956         element.css(options.from);
5957         options.from = null;
5958       }
5959
5960       var closed, runner = new $$AnimateRunner();
5961       return {
5962         start: run,
5963         end: run
5964       };
5965
5966       function run() {
5967         $$rAF(function() {
5968           applyAnimationContents();
5969           if (!closed) {
5970             runner.complete();
5971           }
5972           closed = true;
5973         });
5974         return runner;
5975       }
5976
5977       function applyAnimationContents() {
5978         if (options.addClass) {
5979           element.addClass(options.addClass);
5980           options.addClass = null;
5981         }
5982         if (options.removeClass) {
5983           element.removeClass(options.removeClass);
5984           options.removeClass = null;
5985         }
5986         if (options.to) {
5987           element.css(options.to);
5988           options.to = null;
5989         }
5990       }
5991     };
5992   }];
5993 };
5994
5995 /* global stripHash: true */
5996
5997 /**
5998  * ! This is a private undocumented service !
5999  *
6000  * @name $browser
6001  * @requires $log
6002  * @description
6003  * This object has two goals:
6004  *
6005  * - hide all the global state in the browser caused by the window object
6006  * - abstract away all the browser specific features and inconsistencies
6007  *
6008  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
6009  * service, which can be used for convenient testing of the application without the interaction with
6010  * the real browser apis.
6011  */
6012 /**
6013  * @param {object} window The global window object.
6014  * @param {object} document jQuery wrapped document.
6015  * @param {object} $log window.console or an object with the same interface.
6016  * @param {object} $sniffer $sniffer service
6017  */
6018 function Browser(window, document, $log, $sniffer) {
6019   var self = this,
6020       location = window.location,
6021       history = window.history,
6022       setTimeout = window.setTimeout,
6023       clearTimeout = window.clearTimeout,
6024       pendingDeferIds = {};
6025
6026   self.isMock = false;
6027
6028   var outstandingRequestCount = 0;
6029   var outstandingRequestCallbacks = [];
6030
6031   // TODO(vojta): remove this temporary api
6032   self.$$completeOutstandingRequest = completeOutstandingRequest;
6033   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
6034
6035   /**
6036    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
6037    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
6038    */
6039   function completeOutstandingRequest(fn) {
6040     try {
6041       fn.apply(null, sliceArgs(arguments, 1));
6042     } finally {
6043       outstandingRequestCount--;
6044       if (outstandingRequestCount === 0) {
6045         while (outstandingRequestCallbacks.length) {
6046           try {
6047             outstandingRequestCallbacks.pop()();
6048           } catch (e) {
6049             $log.error(e);
6050           }
6051         }
6052       }
6053     }
6054   }
6055
6056   function getHash(url) {
6057     var index = url.indexOf('#');
6058     return index === -1 ? '' : url.substr(index);
6059   }
6060
6061   /**
6062    * @private
6063    * Note: this method is used only by scenario runner
6064    * TODO(vojta): prefix this method with $$ ?
6065    * @param {function()} callback Function that will be called when no outstanding request
6066    */
6067   self.notifyWhenNoOutstandingRequests = function(callback) {
6068     if (outstandingRequestCount === 0) {
6069       callback();
6070     } else {
6071       outstandingRequestCallbacks.push(callback);
6072     }
6073   };
6074
6075   //////////////////////////////////////////////////////////////
6076   // URL API
6077   //////////////////////////////////////////////////////////////
6078
6079   var cachedState, lastHistoryState,
6080       lastBrowserUrl = location.href,
6081       baseElement = document.find('base'),
6082       pendingLocation = null,
6083       getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
6084         try {
6085           return history.state;
6086         } catch (e) {
6087           // MSIE can reportedly throw when there is no state (UNCONFIRMED).
6088         }
6089       };
6090
6091   cacheState();
6092   lastHistoryState = cachedState;
6093
6094   /**
6095    * @name $browser#url
6096    *
6097    * @description
6098    * GETTER:
6099    * Without any argument, this method just returns current value of location.href.
6100    *
6101    * SETTER:
6102    * With at least one argument, this method sets url to new value.
6103    * If html5 history api supported, pushState/replaceState is used, otherwise
6104    * location.href/location.replace is used.
6105    * Returns its own instance to allow chaining
6106    *
6107    * NOTE: this api is intended for use only by the $location service. Please use the
6108    * {@link ng.$location $location service} to change url.
6109    *
6110    * @param {string} url New url (when used as setter)
6111    * @param {boolean=} replace Should new url replace current history record?
6112    * @param {object=} state object to use with pushState/replaceState
6113    */
6114   self.url = function(url, replace, state) {
6115     // In modern browsers `history.state` is `null` by default; treating it separately
6116     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
6117     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
6118     if (isUndefined(state)) {
6119       state = null;
6120     }
6121
6122     // Android Browser BFCache causes location, history reference to become stale.
6123     if (location !== window.location) location = window.location;
6124     if (history !== window.history) history = window.history;
6125
6126     // setter
6127     if (url) {
6128       var sameState = lastHistoryState === state;
6129
6130       // Don't change anything if previous and current URLs and states match. This also prevents
6131       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
6132       // See https://github.com/angular/angular.js/commit/ffb2701
6133       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
6134         return self;
6135       }
6136       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
6137       lastBrowserUrl = url;
6138       lastHistoryState = state;
6139       // Don't use history API if only the hash changed
6140       // due to a bug in IE10/IE11 which leads
6141       // to not firing a `hashchange` nor `popstate` event
6142       // in some cases (see #9143).
6143       if ($sniffer.history && (!sameBase || !sameState)) {
6144         history[replace ? 'replaceState' : 'pushState'](state, '', url);
6145         cacheState();
6146         // Do the assignment again so that those two variables are referentially identical.
6147         lastHistoryState = cachedState;
6148       } else {
6149         if (!sameBase) {
6150           pendingLocation = url;
6151         }
6152         if (replace) {
6153           location.replace(url);
6154         } else if (!sameBase) {
6155           location.href = url;
6156         } else {
6157           location.hash = getHash(url);
6158         }
6159         if (location.href !== url) {
6160           pendingLocation = url;
6161         }
6162       }
6163       if (pendingLocation) {
6164         pendingLocation = url;
6165       }
6166       return self;
6167     // getter
6168     } else {
6169       // - pendingLocation is needed as browsers don't allow to read out
6170       //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
6171       //   https://openradar.appspot.com/22186109).
6172       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
6173       return pendingLocation || location.href.replace(/%27/g,'\'');
6174     }
6175   };
6176
6177   /**
6178    * @name $browser#state
6179    *
6180    * @description
6181    * This method is a getter.
6182    *
6183    * Return history.state or null if history.state is undefined.
6184    *
6185    * @returns {object} state
6186    */
6187   self.state = function() {
6188     return cachedState;
6189   };
6190
6191   var urlChangeListeners = [],
6192       urlChangeInit = false;
6193
6194   function cacheStateAndFireUrlChange() {
6195     pendingLocation = null;
6196     cacheState();
6197     fireUrlChange();
6198   }
6199
6200   // This variable should be used *only* inside the cacheState function.
6201   var lastCachedState = null;
6202   function cacheState() {
6203     // This should be the only place in $browser where `history.state` is read.
6204     cachedState = getCurrentState();
6205     cachedState = isUndefined(cachedState) ? null : cachedState;
6206
6207     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
6208     if (equals(cachedState, lastCachedState)) {
6209       cachedState = lastCachedState;
6210     }
6211     lastCachedState = cachedState;
6212   }
6213
6214   function fireUrlChange() {
6215     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
6216       return;
6217     }
6218
6219     lastBrowserUrl = self.url();
6220     lastHistoryState = cachedState;
6221     forEach(urlChangeListeners, function(listener) {
6222       listener(self.url(), cachedState);
6223     });
6224   }
6225
6226   /**
6227    * @name $browser#onUrlChange
6228    *
6229    * @description
6230    * Register callback function that will be called, when url changes.
6231    *
6232    * It's only called when the url is changed from outside of angular:
6233    * - user types different url into address bar
6234    * - user clicks on history (forward/back) button
6235    * - user clicks on a link
6236    *
6237    * It's not called when url is changed by $browser.url() method
6238    *
6239    * The listener gets called with new url as parameter.
6240    *
6241    * NOTE: this api is intended for use only by the $location service. Please use the
6242    * {@link ng.$location $location service} to monitor url changes in angular apps.
6243    *
6244    * @param {function(string)} listener Listener function to be called when url changes.
6245    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
6246    */
6247   self.onUrlChange = function(callback) {
6248     // TODO(vojta): refactor to use node's syntax for events
6249     if (!urlChangeInit) {
6250       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
6251       // don't fire popstate when user change the address bar and don't fire hashchange when url
6252       // changed by push/replaceState
6253
6254       // html5 history api - popstate event
6255       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
6256       // hashchange event
6257       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
6258
6259       urlChangeInit = true;
6260     }
6261
6262     urlChangeListeners.push(callback);
6263     return callback;
6264   };
6265
6266   /**
6267    * @private
6268    * Remove popstate and hashchange handler from window.
6269    *
6270    * NOTE: this api is intended for use only by $rootScope.
6271    */
6272   self.$$applicationDestroyed = function() {
6273     jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
6274   };
6275
6276   /**
6277    * Checks whether the url has changed outside of Angular.
6278    * Needs to be exported to be able to check for changes that have been done in sync,
6279    * as hashchange/popstate events fire in async.
6280    */
6281   self.$$checkUrlChange = fireUrlChange;
6282
6283   //////////////////////////////////////////////////////////////
6284   // Misc API
6285   //////////////////////////////////////////////////////////////
6286
6287   /**
6288    * @name $browser#baseHref
6289    *
6290    * @description
6291    * Returns current <base href>
6292    * (always relative - without domain)
6293    *
6294    * @returns {string} The current base href
6295    */
6296   self.baseHref = function() {
6297     var href = baseElement.attr('href');
6298     return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : '';
6299   };
6300
6301   /**
6302    * @name $browser#defer
6303    * @param {function()} fn A function, who's execution should be deferred.
6304    * @param {number=} [delay=0] of milliseconds to defer the function execution.
6305    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
6306    *
6307    * @description
6308    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
6309    *
6310    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
6311    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
6312    * via `$browser.defer.flush()`.
6313    *
6314    */
6315   self.defer = function(fn, delay) {
6316     var timeoutId;
6317     outstandingRequestCount++;
6318     timeoutId = setTimeout(function() {
6319       delete pendingDeferIds[timeoutId];
6320       completeOutstandingRequest(fn);
6321     }, delay || 0);
6322     pendingDeferIds[timeoutId] = true;
6323     return timeoutId;
6324   };
6325
6326
6327   /**
6328    * @name $browser#defer.cancel
6329    *
6330    * @description
6331    * Cancels a deferred task identified with `deferId`.
6332    *
6333    * @param {*} deferId Token returned by the `$browser.defer` function.
6334    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
6335    *                    canceled.
6336    */
6337   self.defer.cancel = function(deferId) {
6338     if (pendingDeferIds[deferId]) {
6339       delete pendingDeferIds[deferId];
6340       clearTimeout(deferId);
6341       completeOutstandingRequest(noop);
6342       return true;
6343     }
6344     return false;
6345   };
6346
6347 }
6348
6349 /** @this */
6350 function $BrowserProvider() {
6351   this.$get = ['$window', '$log', '$sniffer', '$document',
6352       function($window, $log, $sniffer, $document) {
6353         return new Browser($window, $document, $log, $sniffer);
6354       }];
6355 }
6356
6357 /**
6358  * @ngdoc service
6359  * @name $cacheFactory
6360  * @this
6361  *
6362  * @description
6363  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
6364  * them.
6365  *
6366  * ```js
6367  *
6368  *  var cache = $cacheFactory('cacheId');
6369  *  expect($cacheFactory.get('cacheId')).toBe(cache);
6370  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
6371  *
6372  *  cache.put("key", "value");
6373  *  cache.put("another key", "another value");
6374  *
6375  *  // We've specified no options on creation
6376  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
6377  *
6378  * ```
6379  *
6380  *
6381  * @param {string} cacheId Name or id of the newly created cache.
6382  * @param {object=} options Options object that specifies the cache behavior. Properties:
6383  *
6384  *   - `{number=}` `capacity` â€” turns the cache into LRU cache.
6385  *
6386  * @returns {object} Newly created cache object with the following set of methods:
6387  *
6388  * - `{object}` `info()` â€” Returns id, size, and options of cache.
6389  * - `{{*}}` `put({string} key, {*} value)` â€” Puts a new key-value pair into the cache and returns
6390  *   it.
6391  * - `{{*}}` `get({string} key)` â€” Returns cached value for `key` or undefined for cache miss.
6392  * - `{void}` `remove({string} key)` â€” Removes a key-value pair from the cache.
6393  * - `{void}` `removeAll()` â€” Removes all cached values.
6394  * - `{void}` `destroy()` â€” Removes references to this cache from $cacheFactory.
6395  *
6396  * @example
6397    <example module="cacheExampleApp" name="cache-factory">
6398      <file name="index.html">
6399        <div ng-controller="CacheController">
6400          <input ng-model="newCacheKey" placeholder="Key">
6401          <input ng-model="newCacheValue" placeholder="Value">
6402          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
6403
6404          <p ng-if="keys.length">Cached Values</p>
6405          <div ng-repeat="key in keys">
6406            <span ng-bind="key"></span>
6407            <span>: </span>
6408            <b ng-bind="cache.get(key)"></b>
6409          </div>
6410
6411          <p>Cache Info</p>
6412          <div ng-repeat="(key, value) in cache.info()">
6413            <span ng-bind="key"></span>
6414            <span>: </span>
6415            <b ng-bind="value"></b>
6416          </div>
6417        </div>
6418      </file>
6419      <file name="script.js">
6420        angular.module('cacheExampleApp', []).
6421          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
6422            $scope.keys = [];
6423            $scope.cache = $cacheFactory('cacheId');
6424            $scope.put = function(key, value) {
6425              if (angular.isUndefined($scope.cache.get(key))) {
6426                $scope.keys.push(key);
6427              }
6428              $scope.cache.put(key, angular.isUndefined(value) ? null : value);
6429            };
6430          }]);
6431      </file>
6432      <file name="style.css">
6433        p {
6434          margin: 10px 0 3px;
6435        }
6436      </file>
6437    </example>
6438  */
6439 function $CacheFactoryProvider() {
6440
6441   this.$get = function() {
6442     var caches = {};
6443
6444     function cacheFactory(cacheId, options) {
6445       if (cacheId in caches) {
6446         throw minErr('$cacheFactory')('iid', 'CacheId \'{0}\' is already taken!', cacheId);
6447       }
6448
6449       var size = 0,
6450           stats = extend({}, options, {id: cacheId}),
6451           data = createMap(),
6452           capacity = (options && options.capacity) || Number.MAX_VALUE,
6453           lruHash = createMap(),
6454           freshEnd = null,
6455           staleEnd = null;
6456
6457       /**
6458        * @ngdoc type
6459        * @name $cacheFactory.Cache
6460        *
6461        * @description
6462        * A cache object used to store and retrieve data, primarily used by
6463        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
6464        * templates and other data.
6465        *
6466        * ```js
6467        *  angular.module('superCache')
6468        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
6469        *      return $cacheFactory('super-cache');
6470        *    }]);
6471        * ```
6472        *
6473        * Example test:
6474        *
6475        * ```js
6476        *  it('should behave like a cache', inject(function(superCache) {
6477        *    superCache.put('key', 'value');
6478        *    superCache.put('another key', 'another value');
6479        *
6480        *    expect(superCache.info()).toEqual({
6481        *      id: 'super-cache',
6482        *      size: 2
6483        *    });
6484        *
6485        *    superCache.remove('another key');
6486        *    expect(superCache.get('another key')).toBeUndefined();
6487        *
6488        *    superCache.removeAll();
6489        *    expect(superCache.info()).toEqual({
6490        *      id: 'super-cache',
6491        *      size: 0
6492        *    });
6493        *  }));
6494        * ```
6495        */
6496       return (caches[cacheId] = {
6497
6498         /**
6499          * @ngdoc method
6500          * @name $cacheFactory.Cache#put
6501          * @kind function
6502          *
6503          * @description
6504          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
6505          * retrieved later, and incrementing the size of the cache if the key was not already
6506          * present in the cache. If behaving like an LRU cache, it will also remove stale
6507          * entries from the set.
6508          *
6509          * It will not insert undefined values into the cache.
6510          *
6511          * @param {string} key the key under which the cached data is stored.
6512          * @param {*} value the value to store alongside the key. If it is undefined, the key
6513          *    will not be stored.
6514          * @returns {*} the value stored.
6515          */
6516         put: function(key, value) {
6517           if (isUndefined(value)) return;
6518           if (capacity < Number.MAX_VALUE) {
6519             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
6520
6521             refresh(lruEntry);
6522           }
6523
6524           if (!(key in data)) size++;
6525           data[key] = value;
6526
6527           if (size > capacity) {
6528             this.remove(staleEnd.key);
6529           }
6530
6531           return value;
6532         },
6533
6534         /**
6535          * @ngdoc method
6536          * @name $cacheFactory.Cache#get
6537          * @kind function
6538          *
6539          * @description
6540          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
6541          *
6542          * @param {string} key the key of the data to be retrieved
6543          * @returns {*} the value stored.
6544          */
6545         get: function(key) {
6546           if (capacity < Number.MAX_VALUE) {
6547             var lruEntry = lruHash[key];
6548
6549             if (!lruEntry) return;
6550
6551             refresh(lruEntry);
6552           }
6553
6554           return data[key];
6555         },
6556
6557
6558         /**
6559          * @ngdoc method
6560          * @name $cacheFactory.Cache#remove
6561          * @kind function
6562          *
6563          * @description
6564          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
6565          *
6566          * @param {string} key the key of the entry to be removed
6567          */
6568         remove: function(key) {
6569           if (capacity < Number.MAX_VALUE) {
6570             var lruEntry = lruHash[key];
6571
6572             if (!lruEntry) return;
6573
6574             if (lruEntry === freshEnd) freshEnd = lruEntry.p;
6575             if (lruEntry === staleEnd) staleEnd = lruEntry.n;
6576             link(lruEntry.n,lruEntry.p);
6577
6578             delete lruHash[key];
6579           }
6580
6581           if (!(key in data)) return;
6582
6583           delete data[key];
6584           size--;
6585         },
6586
6587
6588         /**
6589          * @ngdoc method
6590          * @name $cacheFactory.Cache#removeAll
6591          * @kind function
6592          *
6593          * @description
6594          * Clears the cache object of any entries.
6595          */
6596         removeAll: function() {
6597           data = createMap();
6598           size = 0;
6599           lruHash = createMap();
6600           freshEnd = staleEnd = null;
6601         },
6602
6603
6604         /**
6605          * @ngdoc method
6606          * @name $cacheFactory.Cache#destroy
6607          * @kind function
6608          *
6609          * @description
6610          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
6611          * removing it from the {@link $cacheFactory $cacheFactory} set.
6612          */
6613         destroy: function() {
6614           data = null;
6615           stats = null;
6616           lruHash = null;
6617           delete caches[cacheId];
6618         },
6619
6620
6621         /**
6622          * @ngdoc method
6623          * @name $cacheFactory.Cache#info
6624          * @kind function
6625          *
6626          * @description
6627          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
6628          *
6629          * @returns {object} an object with the following properties:
6630          *   <ul>
6631          *     <li>**id**: the id of the cache instance</li>
6632          *     <li>**size**: the number of entries kept in the cache instance</li>
6633          *     <li>**...**: any additional properties from the options object when creating the
6634          *       cache.</li>
6635          *   </ul>
6636          */
6637         info: function() {
6638           return extend({}, stats, {size: size});
6639         }
6640       });
6641
6642
6643       /**
6644        * makes the `entry` the freshEnd of the LRU linked list
6645        */
6646       function refresh(entry) {
6647         if (entry !== freshEnd) {
6648           if (!staleEnd) {
6649             staleEnd = entry;
6650           } else if (staleEnd === entry) {
6651             staleEnd = entry.n;
6652           }
6653
6654           link(entry.n, entry.p);
6655           link(entry, freshEnd);
6656           freshEnd = entry;
6657           freshEnd.n = null;
6658         }
6659       }
6660
6661
6662       /**
6663        * bidirectionally links two entries of the LRU linked list
6664        */
6665       function link(nextEntry, prevEntry) {
6666         if (nextEntry !== prevEntry) {
6667           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
6668           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
6669         }
6670       }
6671     }
6672
6673
6674   /**
6675    * @ngdoc method
6676    * @name $cacheFactory#info
6677    *
6678    * @description
6679    * Get information about all the caches that have been created
6680    *
6681    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6682    */
6683     cacheFactory.info = function() {
6684       var info = {};
6685       forEach(caches, function(cache, cacheId) {
6686         info[cacheId] = cache.info();
6687       });
6688       return info;
6689     };
6690
6691
6692   /**
6693    * @ngdoc method
6694    * @name $cacheFactory#get
6695    *
6696    * @description
6697    * Get access to a cache object by the `cacheId` used when it was created.
6698    *
6699    * @param {string} cacheId Name or id of a cache to access.
6700    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6701    */
6702     cacheFactory.get = function(cacheId) {
6703       return caches[cacheId];
6704     };
6705
6706
6707     return cacheFactory;
6708   };
6709 }
6710
6711 /**
6712  * @ngdoc service
6713  * @name $templateCache
6714  * @this
6715  *
6716  * @description
6717  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6718  * can load templates directly into the cache in a `script` tag, or by consuming the
6719  * `$templateCache` service directly.
6720  *
6721  * Adding via the `script` tag:
6722  *
6723  * ```html
6724  *   <script type="text/ng-template" id="templateId.html">
6725  *     <p>This is the content of the template</p>
6726  *   </script>
6727  * ```
6728  *
6729  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6730  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6731  * element with ng-app attribute), otherwise the template will be ignored.
6732  *
6733  * Adding via the `$templateCache` service:
6734  *
6735  * ```js
6736  * var myApp = angular.module('myApp', []);
6737  * myApp.run(function($templateCache) {
6738  *   $templateCache.put('templateId.html', 'This is the content of the template');
6739  * });
6740  * ```
6741  *
6742  * To retrieve the template later, simply use it in your component:
6743  * ```js
6744  * myApp.component('myComponent', {
6745  *    templateUrl: 'templateId.html'
6746  * });
6747  * ```
6748  *
6749  * or get it via the `$templateCache` service:
6750  * ```js
6751  * $templateCache.get('templateId.html')
6752  * ```
6753  *
6754  * See {@link ng.$cacheFactory $cacheFactory}.
6755  *
6756  */
6757 function $TemplateCacheProvider() {
6758   this.$get = ['$cacheFactory', function($cacheFactory) {
6759     return $cacheFactory('templates');
6760   }];
6761 }
6762
6763 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6764  *     Any commits to this file should be reviewed with security in mind.  *
6765  *   Changes to this file can potentially create security vulnerabilities. *
6766  *          An approval from 2 Core members with history of modifying      *
6767  *                         this file is required.                          *
6768  *                                                                         *
6769  *  Does the change somehow allow for arbitrary javascript to be executed? *
6770  *    Or allows for someone to change the prototype of built-in objects?   *
6771  *     Or gives undesired access to variables like document or window?    *
6772  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6773
6774 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6775  *
6776  * DOM-related variables:
6777  *
6778  * - "node" - DOM Node
6779  * - "element" - DOM Element or Node
6780  * - "$node" or "$element" - jqLite-wrapped node or element
6781  *
6782  *
6783  * Compiler related stuff:
6784  *
6785  * - "linkFn" - linking fn of a single directive
6786  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6787  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6788  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6789  */
6790
6791
6792 /**
6793  * @ngdoc service
6794  * @name $compile
6795  * @kind function
6796  *
6797  * @description
6798  * Compiles an HTML string or DOM into a template and produces a template function, which
6799  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6800  *
6801  * The compilation is a process of walking the DOM tree and matching DOM elements to
6802  * {@link ng.$compileProvider#directive directives}.
6803  *
6804  * <div class="alert alert-warning">
6805  * **Note:** This document is an in-depth reference of all directive options.
6806  * For a gentle introduction to directives with examples of common use cases,
6807  * see the {@link guide/directive directive guide}.
6808  * </div>
6809  *
6810  * ## Comprehensive Directive API
6811  *
6812  * There are many different options for a directive.
6813  *
6814  * The difference resides in the return value of the factory function.
6815  * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
6816  * that defines the directive properties, or just the `postLink` function (all other properties will have
6817  * the default values).
6818  *
6819  * <div class="alert alert-success">
6820  * **Best Practice:** It's recommended to use the "directive definition object" form.
6821  * </div>
6822  *
6823  * Here's an example directive declared with a Directive Definition Object:
6824  *
6825  * ```js
6826  *   var myModule = angular.module(...);
6827  *
6828  *   myModule.directive('directiveName', function factory(injectables) {
6829  *     var directiveDefinitionObject = {
6830  *       {@link $compile#-priority- priority}: 0,
6831  *       {@link $compile#-template- template}: '<div></div>', // or // function(tElement, tAttrs) { ... },
6832  *       // or
6833  *       // {@link $compile#-templateurl- templateUrl}: 'directive.html', // or // function(tElement, tAttrs) { ... },
6834  *       {@link $compile#-transclude- transclude}: false,
6835  *       {@link $compile#-restrict- restrict}: 'A',
6836  *       {@link $compile#-templatenamespace- templateNamespace}: 'html',
6837  *       {@link $compile#-scope- scope}: false,
6838  *       {@link $compile#-controller- controller}: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6839  *       {@link $compile#-controlleras- controllerAs}: 'stringIdentifier',
6840  *       {@link $compile#-bindtocontroller- bindToController}: false,
6841  *       {@link $compile#-require- require}: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6842  *       {@link $compile#-multielement- multiElement}: false,
6843  *       {@link $compile#-compile- compile}: function compile(tElement, tAttrs, transclude) {
6844  *         return {
6845  *            {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
6846  *            {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
6847  *         }
6848  *         // or
6849  *         // return function postLink( ... ) { ... }
6850  *       },
6851  *       // or
6852  *       // {@link $compile#-link- link}: {
6853  *       //  {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
6854  *       //  {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
6855  *       // }
6856  *       // or
6857  *       // {@link $compile#-link- link}: function postLink( ... ) { ... }
6858  *     };
6859  *     return directiveDefinitionObject;
6860  *   });
6861  * ```
6862  *
6863  * <div class="alert alert-warning">
6864  * **Note:** Any unspecified options will use the default value. You can see the default values below.
6865  * </div>
6866  *
6867  * Therefore the above can be simplified as:
6868  *
6869  * ```js
6870  *   var myModule = angular.module(...);
6871  *
6872  *   myModule.directive('directiveName', function factory(injectables) {
6873  *     var directiveDefinitionObject = {
6874  *       link: function postLink(scope, iElement, iAttrs) { ... }
6875  *     };
6876  *     return directiveDefinitionObject;
6877  *     // or
6878  *     // return function postLink(scope, iElement, iAttrs) { ... }
6879  *   });
6880  * ```
6881  *
6882  * ### Life-cycle hooks
6883  * Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the
6884  * directive:
6885  * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
6886  *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
6887  *   this element). This is a good place to put initialization code for your controller.
6888  * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
6889  *   `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
6890  *   object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
6891  *   component such as cloning the bound value to prevent accidental mutation of the outer value.
6892  * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
6893  *   changes. Any actions that you wish to take in response to the changes that you detect must be
6894  *   invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
6895  *   could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not
6896  *   be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
6897  *   if detecting changes, you must store the previous value(s) for comparison to the current values.
6898  * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
6899  *   external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
6900  *   the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
6901  *   components will have their `$onDestroy()` hook called before child components.
6902  * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
6903  *   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
6904  *   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
6905  *   they are waiting for their template to load asynchronously and their own compilation and linking has been
6906  *   suspended until that occurs.
6907  *
6908  * #### Comparison with Angular 2 life-cycle hooks
6909  * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are
6910  * some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2:
6911  *
6912  * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.
6913  * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.
6914  *   In Angular 2 you can only define hooks on the prototype of the Component class.
6915  * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to
6916  *   `ngDoCheck` in Angular 2
6917  * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
6918  *   propagated throughout the application.
6919  *   Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
6920  *   error or do nothing depending upon the state of `enableProdMode()`.
6921  *
6922  * #### Life-cycle hook examples
6923  *
6924  * This example shows how you can check for mutations to a Date object even though the identity of the object
6925  * has not changed.
6926  *
6927  * <example name="doCheckDateExample" module="do-check-module">
6928  *   <file name="app.js">
6929  *     angular.module('do-check-module', [])
6930  *       .component('app', {
6931  *         template:
6932  *           'Month: <input ng-model="$ctrl.month" ng-change="$ctrl.updateDate()">' +
6933  *           'Date: {{ $ctrl.date }}' +
6934  *           '<test date="$ctrl.date"></test>',
6935  *         controller: function() {
6936  *           this.date = new Date();
6937  *           this.month = this.date.getMonth();
6938  *           this.updateDate = function() {
6939  *             this.date.setMonth(this.month);
6940  *           };
6941  *         }
6942  *       })
6943  *       .component('test', {
6944  *         bindings: { date: '<' },
6945  *         template:
6946  *           '<pre>{{ $ctrl.log | json }}</pre>',
6947  *         controller: function() {
6948  *           var previousValue;
6949  *           this.log = [];
6950  *           this.$doCheck = function() {
6951  *             var currentValue = this.date && this.date.valueOf();
6952  *             if (previousValue !== currentValue) {
6953  *               this.log.push('doCheck: date mutated: ' + this.date);
6954  *               previousValue = currentValue;
6955  *             }
6956  *           };
6957  *         }
6958  *       });
6959  *   </file>
6960  *   <file name="index.html">
6961  *     <app></app>
6962  *   </file>
6963  * </example>
6964  *
6965  * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
6966  * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
6967  * arrays or objects can have a negative impact on your application performance)
6968  *
6969  * <example name="doCheckArrayExample" module="do-check-module">
6970  *   <file name="index.html">
6971  *     <div ng-init="items = []">
6972  *       <button ng-click="items.push(items.length)">Add Item</button>
6973  *       <button ng-click="items = []">Reset Items</button>
6974  *       <pre>{{ items }}</pre>
6975  *       <test items="items"></test>
6976  *     </div>
6977  *   </file>
6978  *   <file name="app.js">
6979  *      angular.module('do-check-module', [])
6980  *        .component('test', {
6981  *          bindings: { items: '<' },
6982  *          template:
6983  *            '<pre>{{ $ctrl.log | json }}</pre>',
6984  *          controller: function() {
6985  *            this.log = [];
6986  *
6987  *            this.$doCheck = function() {
6988  *              if (this.items_ref !== this.items) {
6989  *                this.log.push('doCheck: items changed');
6990  *                this.items_ref = this.items;
6991  *              }
6992  *              if (!angular.equals(this.items_clone, this.items)) {
6993  *                this.log.push('doCheck: items mutated');
6994  *                this.items_clone = angular.copy(this.items);
6995  *              }
6996  *            };
6997  *          }
6998  *        });
6999  *   </file>
7000  * </example>
7001  *
7002  *
7003  * ### Directive Definition Object
7004  *
7005  * The directive definition object provides instructions to the {@link ng.$compile
7006  * compiler}. The attributes are:
7007  *
7008  * #### `multiElement`
7009  * When this property is set to true (default is `false`), the HTML compiler will collect DOM nodes between
7010  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
7011  * together as the directive elements. It is recommended that this feature be used on directives
7012  * which are not strictly behavioral (such as {@link ngClick}), and which
7013  * do not manipulate or replace child nodes (such as {@link ngInclude}).
7014  *
7015  * #### `priority`
7016  * When there are multiple directives defined on a single DOM element, sometimes it
7017  * is necessary to specify the order in which the directives are applied. The `priority` is used
7018  * to sort the directives before their `compile` functions get called. Priority is defined as a
7019  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
7020  * are also run in priority order, but post-link functions are run in reverse order. The order
7021  * of directives with the same priority is undefined. The default priority is `0`.
7022  *
7023  * #### `terminal`
7024  * If set to true then the current `priority` will be the last set of directives
7025  * which will execute (any directives at the current priority will still execute
7026  * as the order of execution on same `priority` is undefined). Note that expressions
7027  * and other directives used in the directive's template will also be excluded from execution.
7028  *
7029  * #### `scope`
7030  * The scope property can be `false`, `true`, or an object:
7031  *
7032  * * **`false` (default):** No scope will be created for the directive. The directive will use its
7033  * parent's scope.
7034  *
7035  * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
7036  * the directive's element. If multiple directives on the same element request a new scope,
7037  * only one new scope is created.
7038  *
7039  * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
7040  * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
7041  * scope. This is useful when creating reusable components, which should not accidentally read or modify
7042  * data in the parent scope.
7043  *
7044  * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
7045  * directive's element. These local properties are useful for aliasing values for templates. The keys in
7046  * the object hash map to the name of the property on the isolate scope; the values define how the property
7047  * is bound to the parent scope, via matching attributes on the directive's element:
7048  *
7049  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
7050  *   always a string since DOM attributes are strings. If no `attr` name is specified then the
7051  *   attribute name is assumed to be the same as the local name. Given `<my-component
7052  *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
7053  *   the directive's scope property `localName` will reflect the interpolated value of `hello
7054  *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
7055  *   scope. The `name` is read from the parent scope (not the directive's scope).
7056  *
7057  * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
7058  *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
7059  *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
7060  *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
7061  *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
7062  *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
7063  *   `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
7064  *   `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
7065  *   optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
7066  *   will be thrown upon discovering changes to the local value, since it will be impossible to sync
7067  *   them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
7068  *   method is used for tracking changes, and the equality check is based on object identity.
7069  *   However, if an object literal or an array literal is passed as the binding expression, the
7070  *   equality check is done by value (using the {@link angular.equals} function). It's also possible
7071  *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
7072  *   `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
7073  *
7074   * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
7075  *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
7076  *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
7077  *   local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
7078  *
7079  *   For example, given `<my-component my-attr="parentModel">` and directive definition of
7080  *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
7081  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
7082  *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
7083  *   two caveats:
7084  *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
7085  *     sets the same value. That means if your bound value is an object, changes to its properties
7086  *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
7087  *     2. one-way binding watches changes to the **identity** of the parent value. That means the
7088  *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
7089  *     to the value has changed. In most cases, this should not be of concern, but can be important
7090  *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
7091  *     If you now change a property of the object in your parent scope, the change will not be
7092  *     propagated to the isolated scope, because the identity of the object on the parent scope
7093  *     has not changed. Instead you must assign a new object.
7094  *
7095  *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
7096  *   back to the parent. However, it does not make this completely impossible.
7097  *
7098  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
7099  *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
7100  *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
7101  *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
7102  *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
7103  *   via an expression to the parent scope. This can be done by passing a map of local variable names
7104  *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
7105  *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
7106  *
7107  * In general it's possible to apply more than one directive to one element, but there might be limitations
7108  * depending on the type of scope required by the directives. The following points will help explain these limitations.
7109  * For simplicity only two directives are taken into account, but it is also applicable for several directives:
7110  *
7111  * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
7112  * * **child scope** + **no scope** =>  Both directives will share one single child scope
7113  * * **child scope** + **child scope** =>  Both directives will share one single child scope
7114  * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
7115  * its parent's scope
7116  * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
7117  * be applied to the same element.
7118  * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
7119  * cannot be applied to the same element.
7120  *
7121  *
7122  * #### `bindToController`
7123  * This property is used to bind scope properties directly to the controller. It can be either
7124  * `true` or an object hash with the same format as the `scope` property.
7125  *
7126  * When an isolate scope is used for a directive (see above), `bindToController: true` will
7127  * allow a component to have its properties bound to the controller, rather than to scope.
7128  *
7129  * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
7130  * properties. You can access these bindings once they have been initialized by providing a controller method called
7131  * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
7132  * initialized.
7133  *
7134  * <div class="alert alert-warning">
7135  * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
7136  * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
7137  * code that relies upon bindings inside a `$onInit` method on the controller, instead.
7138  * </div>
7139  *
7140  * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
7141  * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
7142  * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
7143  * scope (useful for component directives).
7144  *
7145  * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
7146  *
7147  *
7148  * #### `controller`
7149  * Controller constructor function. The controller is instantiated before the
7150  * pre-linking phase and can be accessed by other directives (see
7151  * `require` attribute). This allows the directives to communicate with each other and augment
7152  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
7153  *
7154  * * `$scope` - Current scope associated with the element
7155  * * `$element` - Current element
7156  * * `$attrs` - Current attributes object for the element
7157  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
7158  *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
7159  *    * `scope`: (optional) override the scope.
7160  *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
7161  *    * `futureParentElement` (optional):
7162  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
7163  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
7164  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
7165  *          and when the `cloneLinkingFn` is passed,
7166  *          as those elements need to created and cloned in a special way when they are defined outside their
7167  *          usual containers (e.g. like `<svg>`).
7168  *        * See also the `directive.templateNamespace` property.
7169  *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
7170  *      then the default transclusion is provided.
7171  *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
7172  *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
7173  *
7174  * #### `require`
7175  * Require another directive and inject its controller as the fourth argument to the linking function. The
7176  * `require` property can be a string, an array or an object:
7177  * * a **string** containing the name of the directive to pass to the linking function
7178  * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
7179  * linking function will be an array of controllers in the same order as the names in the `require` property
7180  * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
7181  * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
7182  * controllers.
7183  *
7184  * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
7185  * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
7186  * have been constructed but before `$onInit` is called.
7187  * If the name of the required controller is the same as the local name (the key), the name can be
7188  * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.
7189  * See the {@link $compileProvider#component} helper for an example of how this can be used.
7190  * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
7191  * raised (unless no link function is specified and the required controllers are not being bound to the directive
7192  * controller, in which case error checking is skipped). The name can be prefixed with:
7193  *
7194  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
7195  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
7196  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
7197  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
7198  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
7199  *   `null` to the `link` fn if not found.
7200  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
7201  *   `null` to the `link` fn if not found.
7202  *
7203  *
7204  * #### `controllerAs`
7205  * Identifier name for a reference to the controller in the directive's scope.
7206  * This allows the controller to be referenced from the directive template. This is especially
7207  * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
7208  * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
7209  * `controllerAs` reference might overwrite a property that already exists on the parent scope.
7210  *
7211  *
7212  * #### `restrict`
7213  * String of subset of `EACM` which restricts the directive to a specific directive
7214  * declaration style. If omitted, the defaults (elements and attributes) are used.
7215  *
7216  * * `E` - Element name (default): `<my-directive></my-directive>`
7217  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
7218  * * `C` - Class: `<div class="my-directive: exp;"></div>`
7219  * * `M` - Comment: `<!-- directive: my-directive exp -->`
7220  *
7221  *
7222  * #### `templateNamespace`
7223  * String representing the document type used by the markup in the template.
7224  * AngularJS needs this information as those elements need to be created and cloned
7225  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
7226  *
7227  * * `html` - All root nodes in the template are HTML. Root nodes may also be
7228  *   top-level elements such as `<svg>` or `<math>`.
7229  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
7230  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
7231  *
7232  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
7233  *
7234  * #### `template`
7235  * HTML markup that may:
7236  * * Replace the contents of the directive's element (default).
7237  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
7238  * * Wrap the contents of the directive's element (if `transclude` is true).
7239  *
7240  * Value may be:
7241  *
7242  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
7243  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
7244  *   function api below) and returns a string value.
7245  *
7246  *
7247  * #### `templateUrl`
7248  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
7249  *
7250  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
7251  * for later when the template has been resolved.  In the meantime it will continue to compile and link
7252  * sibling and parent elements as though this element had not contained any directives.
7253  *
7254  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
7255  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
7256  * case when only one deeply nested directive has `templateUrl`.
7257  *
7258  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
7259  *
7260  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
7261  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
7262  * a string value representing the url.  In either case, the template URL is passed through {@link
7263  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
7264  *
7265  *
7266  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
7267  * specify what the template should replace. Defaults to `false`.
7268  *
7269  * * `true` - the template will replace the directive's element.
7270  * * `false` - the template will replace the contents of the directive's element.
7271  *
7272  * The replacement process migrates all of the attributes / classes from the old element to the new
7273  * one. See the {@link guide/directive#template-expanding-directive
7274  * Directives Guide} for an example.
7275  *
7276  * There are very few scenarios where element replacement is required for the application function,
7277  * the main one being reusable custom components that are used within SVG contexts
7278  * (because SVG doesn't work with custom elements in the DOM tree).
7279  *
7280  * #### `transclude`
7281  * Extract the contents of the element where the directive appears and make it available to the directive.
7282  * The contents are compiled and provided to the directive as a **transclusion function**. See the
7283  * {@link $compile#transclusion Transclusion} section below.
7284  *
7285  *
7286  * #### `compile`
7287  *
7288  * ```js
7289  *   function compile(tElement, tAttrs, transclude) { ... }
7290  * ```
7291  *
7292  * The compile function deals with transforming the template DOM. Since most directives do not do
7293  * template transformation, it is not used often. The compile function takes the following arguments:
7294  *
7295  *   * `tElement` - template element - The element where the directive has been declared. It is
7296  *     safe to do template transformation on the element and child elements only.
7297  *
7298  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
7299  *     between all directive compile functions.
7300  *
7301  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
7302  *
7303  * <div class="alert alert-warning">
7304  * **Note:** The template instance and the link instance may be different objects if the template has
7305  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
7306  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
7307  * should be done in a linking function rather than in a compile function.
7308  * </div>
7309
7310  * <div class="alert alert-warning">
7311  * **Note:** The compile function cannot handle directives that recursively use themselves in their
7312  * own templates or compile functions. Compiling these directives results in an infinite loop and
7313  * stack overflow errors.
7314  *
7315  * This can be avoided by manually using $compile in the postLink function to imperatively compile
7316  * a directive's template instead of relying on automatic template compilation via `template` or
7317  * `templateUrl` declaration or manual compilation inside the compile function.
7318  * </div>
7319  *
7320  * <div class="alert alert-danger">
7321  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
7322  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
7323  *   to the link function instead.
7324  * </div>
7325
7326  * A compile function can have a return value which can be either a function or an object.
7327  *
7328  * * returning a (post-link) function - is equivalent to registering the linking function via the
7329  *   `link` property of the config object when the compile function is empty.
7330  *
7331  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
7332  *   control when a linking function should be called during the linking phase. See info about
7333  *   pre-linking and post-linking functions below.
7334  *
7335  *
7336  * #### `link`
7337  * This property is used only if the `compile` property is not defined.
7338  *
7339  * ```js
7340  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
7341  * ```
7342  *
7343  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
7344  * executed after the template has been cloned. This is where most of the directive logic will be
7345  * put.
7346  *
7347  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
7348  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
7349  *
7350  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
7351  *     manipulate the children of the element only in `postLink` function since the children have
7352  *     already been linked.
7353  *
7354  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
7355  *     between all directive linking functions.
7356  *
7357  *   * `controller` - the directive's required controller instance(s) - Instances are shared
7358  *     among all directives, which allows the directives to use the controllers as a communication
7359  *     channel. The exact value depends on the directive's `require` property:
7360  *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
7361  *       * `string`: the controller instance
7362  *       * `array`: array of controller instances
7363  *
7364  *     If a required controller cannot be found, and it is optional, the instance is `null`,
7365  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
7366  *
7367  *     Note that you can also require the directive's own controller - it will be made available like
7368  *     any other controller.
7369  *
7370  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
7371  *     This is the same as the `$transclude` parameter of directive controllers,
7372  *     see {@link ng.$compile#-controller- the controller section for details}.
7373  *     `function([scope], cloneLinkingFn, futureParentElement)`.
7374  *
7375  * #### Pre-linking function
7376  *
7377  * Executed before the child elements are linked. Not safe to do DOM transformation since the
7378  * compiler linking function will fail to locate the correct elements for linking.
7379  *
7380  * #### Post-linking function
7381  *
7382  * Executed after the child elements are linked.
7383  *
7384  * Note that child elements that contain `templateUrl` directives will not have been compiled
7385  * and linked since they are waiting for their template to load asynchronously and their own
7386  * compilation and linking has been suspended until that occurs.
7387  *
7388  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
7389  * for their async templates to be resolved.
7390  *
7391  *
7392  * ### Transclusion
7393  *
7394  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
7395  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
7396  * scope from where they were taken.
7397  *
7398  * Transclusion is used (often with {@link ngTransclude}) to insert the
7399  * original contents of a directive's element into a specified place in the template of the directive.
7400  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
7401  * content has access to the properties on the scope from which it was taken, even if the directive
7402  * has isolated scope.
7403  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
7404  *
7405  * This makes it possible for the widget to have private state for its template, while the transcluded
7406  * content has access to its originating scope.
7407  *
7408  * <div class="alert alert-warning">
7409  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
7410  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
7411  * Testing Transclusion Directives}.
7412  * </div>
7413  *
7414  * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
7415  * directive's element, the entire element or multiple parts of the element contents:
7416  *
7417  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
7418  * * `'element'` - transclude the whole of the directive's element including any directives on this
7419  *   element that defined at a lower priority than this directive. When used, the `template`
7420  *   property is ignored.
7421  * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
7422  *
7423  * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
7424  *
7425  * This object is a map where the keys are the name of the slot to fill and the value is an element selector
7426  * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
7427  * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
7428  *
7429  * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7430  *
7431  * If the element selector is prefixed with a `?` then that slot is optional.
7432  *
7433  * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
7434  * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
7435  *
7436  * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
7437  * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
7438  * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
7439  * injectable into the directive's controller.
7440  *
7441  *
7442  * #### Transclusion Functions
7443  *
7444  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
7445  * function** to the directive's `link` function and `controller`. This transclusion function is a special
7446  * **linking function** that will return the compiled contents linked to a new transclusion scope.
7447  *
7448  * <div class="alert alert-info">
7449  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
7450  * ngTransclude will deal with it for us.
7451  * </div>
7452  *
7453  * If you want to manually control the insertion and removal of the transcluded content in your directive
7454  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
7455  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
7456  *
7457  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
7458  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
7459  * content and the `scope` is the newly created transclusion scope, which the clone will be linked to.
7460  *
7461  * <div class="alert alert-info">
7462  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
7463  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
7464  * </div>
7465  *
7466  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
7467  * attach function**:
7468  *
7469  * ```js
7470  * var transcludedContent, transclusionScope;
7471  *
7472  * $transclude(function(clone, scope) {
7473  *   element.append(clone);
7474  *   transcludedContent = clone;
7475  *   transclusionScope = scope;
7476  * });
7477  * ```
7478  *
7479  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
7480  * associated transclusion scope:
7481  *
7482  * ```js
7483  * transcludedContent.remove();
7484  * transclusionScope.$destroy();
7485  * ```
7486  *
7487  * <div class="alert alert-info">
7488  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
7489  * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
7490  * then you are also responsible for calling `$destroy` on the transclusion scope.
7491  * </div>
7492  *
7493  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
7494  * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
7495  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
7496  *
7497  *
7498  * #### Transclusion Scopes
7499  *
7500  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
7501  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
7502  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
7503  * was taken.
7504  *
7505  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
7506  * like this:
7507  *
7508  * ```html
7509  * <div ng-app>
7510  *   <div isolate>
7511  *     <div transclusion>
7512  *     </div>
7513  *   </div>
7514  * </div>
7515  * ```
7516  *
7517  * The `$parent` scope hierarchy will look like this:
7518  *
7519    ```
7520    - $rootScope
7521      - isolate
7522        - transclusion
7523    ```
7524  *
7525  * but the scopes will inherit prototypically from different scopes to their `$parent`.
7526  *
7527    ```
7528    - $rootScope
7529      - transclusion
7530    - isolate
7531    ```
7532  *
7533  *
7534  * ### Attributes
7535  *
7536  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
7537  * `link()` or `compile()` functions. It has a variety of uses.
7538  *
7539  * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
7540  *   'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
7541  *   to the attributes.
7542  *
7543  * * *Directive inter-communication:* All directives share the same instance of the attributes
7544  *   object which allows the directives to use the attributes object as inter directive
7545  *   communication.
7546  *
7547  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
7548  *   allowing other directives to read the interpolated value.
7549  *
7550  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
7551  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
7552  *   the only way to easily get the actual value because during the linking phase the interpolation
7553  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
7554  *
7555  * ```js
7556  * function linkingFn(scope, elm, attrs, ctrl) {
7557  *   // get the attribute value
7558  *   console.log(attrs.ngModel);
7559  *
7560  *   // change the attribute
7561  *   attrs.$set('ngModel', 'new value');
7562  *
7563  *   // observe changes to interpolated attribute
7564  *   attrs.$observe('ngModel', function(value) {
7565  *     console.log('ngModel has changed value to ' + value);
7566  *   });
7567  * }
7568  * ```
7569  *
7570  * ## Example
7571  *
7572  * <div class="alert alert-warning">
7573  * **Note**: Typically directives are registered with `module.directive`. The example below is
7574  * to illustrate how `$compile` works.
7575  * </div>
7576  *
7577  <example module="compileExample" name="compile">
7578    <file name="index.html">
7579     <script>
7580       angular.module('compileExample', [], function($compileProvider) {
7581         // configure new 'compile' directive by passing a directive
7582         // factory function. The factory function injects the '$compile'
7583         $compileProvider.directive('compile', function($compile) {
7584           // directive factory creates a link function
7585           return function(scope, element, attrs) {
7586             scope.$watch(
7587               function(scope) {
7588                  // watch the 'compile' expression for changes
7589                 return scope.$eval(attrs.compile);
7590               },
7591               function(value) {
7592                 // when the 'compile' expression changes
7593                 // assign it into the current DOM
7594                 element.html(value);
7595
7596                 // compile the new DOM and link it to the current
7597                 // scope.
7598                 // NOTE: we only compile .childNodes so that
7599                 // we don't get into infinite loop compiling ourselves
7600                 $compile(element.contents())(scope);
7601               }
7602             );
7603           };
7604         });
7605       })
7606       .controller('GreeterController', ['$scope', function($scope) {
7607         $scope.name = 'Angular';
7608         $scope.html = 'Hello {{name}}';
7609       }]);
7610     </script>
7611     <div ng-controller="GreeterController">
7612       <input ng-model="name"> <br/>
7613       <textarea ng-model="html"></textarea> <br/>
7614       <div compile="html"></div>
7615     </div>
7616    </file>
7617    <file name="protractor.js" type="protractor">
7618      it('should auto compile', function() {
7619        var textarea = $('textarea');
7620        var output = $('div[compile]');
7621        // The initial state reads 'Hello Angular'.
7622        expect(output.getText()).toBe('Hello Angular');
7623        textarea.clear();
7624        textarea.sendKeys('{{name}}!');
7625        expect(output.getText()).toBe('Angular!');
7626      });
7627    </file>
7628  </example>
7629
7630  *
7631  *
7632  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
7633  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
7634  *
7635  * <div class="alert alert-danger">
7636  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
7637  *   e.g. will not use the right outer scope. Please pass the transclude function as a
7638  *   `parentBoundTranscludeFn` to the link function instead.
7639  * </div>
7640  *
7641  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
7642  *                 root element(s), not their children)
7643  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
7644  * (a DOM element/tree) to a scope. Where:
7645  *
7646  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
7647  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
7648  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
7649  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
7650  *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
7651  *
7652  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
7653  *      * `scope` - is the current scope with which the linking function is working with.
7654  *
7655  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
7656  *  keys may be used to control linking behavior:
7657  *
7658  *      * `parentBoundTranscludeFn` - the transclude function made available to
7659  *        directives; if given, it will be passed through to the link functions of
7660  *        directives found in `element` during compilation.
7661  *      * `transcludeControllers` - an object hash with keys that map controller names
7662  *        to a hash with the key `instance`, which maps to the controller instance;
7663  *        if given, it will make the controllers available to directives on the compileNode:
7664  *        ```
7665  *        {
7666  *          parent: {
7667  *            instance: parentControllerInstance
7668  *          }
7669  *        }
7670  *        ```
7671  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
7672  *        the cloned elements; only needed for transcludes that are allowed to contain non html
7673  *        elements (e.g. SVG elements). See also the directive.controller property.
7674  *
7675  * Calling the linking function returns the element of the template. It is either the original
7676  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
7677  *
7678  * After linking the view is not updated until after a call to $digest which typically is done by
7679  * Angular automatically.
7680  *
7681  * If you need access to the bound view, there are two ways to do it:
7682  *
7683  * - If you are not asking the linking function to clone the template, create the DOM element(s)
7684  *   before you send them to the compiler and keep this reference around.
7685  *   ```js
7686  *     var element = $compile('<p>{{total}}</p>')(scope);
7687  *   ```
7688  *
7689  * - if on the other hand, you need the element to be cloned, the view reference from the original
7690  *   example would not point to the clone, but rather to the original template that was cloned. In
7691  *   this case, you can access the clone via the cloneAttachFn:
7692  *   ```js
7693  *     var templateElement = angular.element('<p>{{total}}</p>'),
7694  *         scope = ....;
7695  *
7696  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
7697  *       //attach the clone to DOM document at the right place
7698  *     });
7699  *
7700  *     //now we have reference to the cloned DOM via `clonedElement`
7701  *   ```
7702  *
7703  *
7704  * For information on how the compiler works, see the
7705  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
7706  *
7707  * @knownIssue
7708  *
7709  * ### Double Compilation
7710  *
7711    Double compilation occurs when an already compiled part of the DOM gets
7712    compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues,
7713    and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it
7714    section on double compilation} for an in-depth explanation and ways to avoid it.
7715  *
7716  */
7717
7718 var $compileMinErr = minErr('$compile');
7719
7720 function UNINITIALIZED_VALUE() {}
7721 var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
7722
7723 /**
7724  * @ngdoc provider
7725  * @name $compileProvider
7726  *
7727  * @description
7728  */
7729 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
7730 /** @this */
7731 function $CompileProvider($provide, $$sanitizeUriProvider) {
7732   var hasDirectives = {},
7733       Suffix = 'Directive',
7734       COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/,
7735       CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/,
7736       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
7737       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
7738
7739   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
7740   // The assumption is that future DOM event attribute names will begin with
7741   // 'on' and be composed of only English letters.
7742   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7743   var bindingCache = createMap();
7744
7745   function parseIsolateBindings(scope, directiveName, isController) {
7746     var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
7747
7748     var bindings = createMap();
7749
7750     forEach(scope, function(definition, scopeName) {
7751       if (definition in bindingCache) {
7752         bindings[scopeName] = bindingCache[definition];
7753         return;
7754       }
7755       var match = definition.match(LOCAL_REGEXP);
7756
7757       if (!match) {
7758         throw $compileMinErr('iscp',
7759             'Invalid {3} for directive \'{0}\'.' +
7760             ' Definition: {... {1}: \'{2}\' ...}',
7761             directiveName, scopeName, definition,
7762             (isController ? 'controller bindings definition' :
7763             'isolate scope definition'));
7764       }
7765
7766       bindings[scopeName] = {
7767         mode: match[1][0],
7768         collection: match[2] === '*',
7769         optional: match[3] === '?',
7770         attrName: match[4] || scopeName
7771       };
7772       if (match[4]) {
7773         bindingCache[definition] = bindings[scopeName];
7774       }
7775     });
7776
7777     return bindings;
7778   }
7779
7780   function parseDirectiveBindings(directive, directiveName) {
7781     var bindings = {
7782       isolateScope: null,
7783       bindToController: null
7784     };
7785     if (isObject(directive.scope)) {
7786       if (directive.bindToController === true) {
7787         bindings.bindToController = parseIsolateBindings(directive.scope,
7788                                                          directiveName, true);
7789         bindings.isolateScope = {};
7790       } else {
7791         bindings.isolateScope = parseIsolateBindings(directive.scope,
7792                                                      directiveName, false);
7793       }
7794     }
7795     if (isObject(directive.bindToController)) {
7796       bindings.bindToController =
7797           parseIsolateBindings(directive.bindToController, directiveName, true);
7798     }
7799     if (bindings.bindToController && !directive.controller) {
7800       // There is no controller
7801       throw $compileMinErr('noctrl',
7802             'Cannot bind to controller without directive \'{0}\'s controller.',
7803             directiveName);
7804     }
7805     return bindings;
7806   }
7807
7808   function assertValidDirectiveName(name) {
7809     var letter = name.charAt(0);
7810     if (!letter || letter !== lowercase(letter)) {
7811       throw $compileMinErr('baddir', 'Directive/Component name \'{0}\' is invalid. The first character must be a lowercase letter', name);
7812     }
7813     if (name !== name.trim()) {
7814       throw $compileMinErr('baddir',
7815             'Directive/Component name \'{0}\' is invalid. The name should not contain leading or trailing whitespaces',
7816             name);
7817     }
7818   }
7819
7820   function getDirectiveRequire(directive) {
7821     var require = directive.require || (directive.controller && directive.name);
7822
7823     if (!isArray(require) && isObject(require)) {
7824       forEach(require, function(value, key) {
7825         var match = value.match(REQUIRE_PREFIX_REGEXP);
7826         var name = value.substring(match[0].length);
7827         if (!name) require[key] = match[0] + key;
7828       });
7829     }
7830
7831     return require;
7832   }
7833
7834   function getDirectiveRestrict(restrict, name) {
7835     if (restrict && !(isString(restrict) && /[EACM]/.test(restrict))) {
7836       throw $compileMinErr('badrestrict',
7837           'Restrict property \'{0}\' of directive \'{1}\' is invalid',
7838           restrict,
7839           name);
7840     }
7841
7842     return restrict || 'EA';
7843   }
7844
7845   /**
7846    * @ngdoc method
7847    * @name $compileProvider#directive
7848    * @kind function
7849    *
7850    * @description
7851    * Register a new directive with the compiler.
7852    *
7853    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7854    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7855    *    names and the values are the factories.
7856    * @param {Function|Array} directiveFactory An injectable directive factory function. See the
7857    *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
7858    * @returns {ng.$compileProvider} Self for chaining.
7859    */
7860   this.directive = function registerDirective(name, directiveFactory) {
7861     assertArg(name, 'name');
7862     assertNotHasOwnProperty(name, 'directive');
7863     if (isString(name)) {
7864       assertValidDirectiveName(name);
7865       assertArg(directiveFactory, 'directiveFactory');
7866       if (!hasDirectives.hasOwnProperty(name)) {
7867         hasDirectives[name] = [];
7868         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
7869           function($injector, $exceptionHandler) {
7870             var directives = [];
7871             forEach(hasDirectives[name], function(directiveFactory, index) {
7872               try {
7873                 var directive = $injector.invoke(directiveFactory);
7874                 if (isFunction(directive)) {
7875                   directive = { compile: valueFn(directive) };
7876                 } else if (!directive.compile && directive.link) {
7877                   directive.compile = valueFn(directive.link);
7878                 }
7879                 directive.priority = directive.priority || 0;
7880                 directive.index = index;
7881                 directive.name = directive.name || name;
7882                 directive.require = getDirectiveRequire(directive);
7883                 directive.restrict = getDirectiveRestrict(directive.restrict, name);
7884                 directive.$$moduleName = directiveFactory.$$moduleName;
7885                 directives.push(directive);
7886               } catch (e) {
7887                 $exceptionHandler(e);
7888               }
7889             });
7890             return directives;
7891           }]);
7892       }
7893       hasDirectives[name].push(directiveFactory);
7894     } else {
7895       forEach(name, reverseParams(registerDirective));
7896     }
7897     return this;
7898   };
7899
7900   /**
7901    * @ngdoc method
7902    * @name $compileProvider#component
7903    * @module ng
7904    * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
7905    * @param {Object} options Component definition object (a simplified
7906    *    {@link ng.$compile#directive-definition-object directive definition object}),
7907    *    with the following properties (all optional):
7908    *
7909    *    - `controller` â€“ `{(string|function()=}` â€“ controller constructor function that should be
7910    *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
7911    *      registered controller} if passed as a string. An empty `noop` function by default.
7912    *    - `controllerAs` â€“ `{string=}` â€“ identifier name for to reference the controller in the component's scope.
7913    *      If present, the controller will be published to scope under the `controllerAs` name.
7914    *      If not present, this will default to be `$ctrl`.
7915    *    - `template` â€“ `{string=|function()=}` â€“ html template as a string or a function that
7916    *      returns an html template as a string which should be used as the contents of this component.
7917    *      Empty string by default.
7918    *
7919    *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
7920    *      the following locals:
7921    *
7922    *      - `$element` - Current element
7923    *      - `$attrs` - Current attributes object for the element
7924    *
7925    *    - `templateUrl` â€“ `{string=|function()=}` â€“ path or function that returns a path to an html
7926    *      template that should be used  as the contents of this component.
7927    *
7928    *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
7929    *      the following locals:
7930    *
7931    *      - `$element` - Current element
7932    *      - `$attrs` - Current attributes object for the element
7933    *
7934    *    - `bindings` â€“ `{object=}` â€“ defines bindings between DOM attributes and component properties.
7935    *      Component properties are always bound to the component controller and not to the scope.
7936    *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
7937    *    - `transclude` â€“ `{boolean=}` â€“ whether {@link $compile#transclusion content transclusion} is enabled.
7938    *      Disabled by default.
7939    *    - `require` - `{Object<string, string>=}` - requires the controllers of other directives and binds them to
7940    *      this component's controller. The object keys specify the property names under which the required
7941    *      controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
7942    *    - `$...` â€“ additional properties to attach to the directive factory function and the controller
7943    *      constructor function. (This is used by the component router to annotate)
7944    *
7945    * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
7946    * @description
7947    * Register a **component definition** with the compiler. This is a shorthand for registering a special
7948    * type of directive, which represents a self-contained UI component in your application. Such components
7949    * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
7950    *
7951    * Component definitions are very simple and do not require as much configuration as defining general
7952    * directives. Component definitions usually consist only of a template and a controller backing it.
7953    *
7954    * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
7955    * `bindToController`. They always have **isolate scope** and are restricted to elements.
7956    *
7957    * Here are a few examples of how you would usually define components:
7958    *
7959    * ```js
7960    *   var myMod = angular.module(...);
7961    *   myMod.component('myComp', {
7962    *     template: '<div>My name is {{$ctrl.name}}</div>',
7963    *     controller: function() {
7964    *       this.name = 'shahar';
7965    *     }
7966    *   });
7967    *
7968    *   myMod.component('myComp', {
7969    *     template: '<div>My name is {{$ctrl.name}}</div>',
7970    *     bindings: {name: '@'}
7971    *   });
7972    *
7973    *   myMod.component('myComp', {
7974    *     templateUrl: 'views/my-comp.html',
7975    *     controller: 'MyCtrl',
7976    *     controllerAs: 'ctrl',
7977    *     bindings: {name: '@'}
7978    *   });
7979    *
7980    * ```
7981    * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
7982    *
7983    * <br />
7984    * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
7985    */
7986   this.component = function registerComponent(name, options) {
7987     var controller = options.controller || function() {};
7988
7989     function factory($injector) {
7990       function makeInjectable(fn) {
7991         if (isFunction(fn) || isArray(fn)) {
7992           return /** @this */ function(tElement, tAttrs) {
7993             return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
7994           };
7995         } else {
7996           return fn;
7997         }
7998       }
7999
8000       var template = (!options.template && !options.templateUrl ? '' : options.template);
8001       var ddo = {
8002         controller: controller,
8003         controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
8004         template: makeInjectable(template),
8005         templateUrl: makeInjectable(options.templateUrl),
8006         transclude: options.transclude,
8007         scope: {},
8008         bindToController: options.bindings || {},
8009         restrict: 'E',
8010         require: options.require
8011       };
8012
8013       // Copy annotations (starting with $) over to the DDO
8014       forEach(options, function(val, key) {
8015         if (key.charAt(0) === '$') ddo[key] = val;
8016       });
8017
8018       return ddo;
8019     }
8020
8021     // TODO(pete) remove the following `forEach` before we release 1.6.0
8022     // The component-router@0.2.0 looks for the annotations on the controller constructor
8023     // Nothing in Angular looks for annotations on the factory function but we can't remove
8024     // it from 1.5.x yet.
8025
8026     // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
8027     // These could be used by libraries such as the new component router
8028     forEach(options, function(val, key) {
8029       if (key.charAt(0) === '$') {
8030         factory[key] = val;
8031         // Don't try to copy over annotations to named controller
8032         if (isFunction(controller)) controller[key] = val;
8033       }
8034     });
8035
8036     factory.$inject = ['$injector'];
8037
8038     return this.directive(name, factory);
8039   };
8040
8041
8042   /**
8043    * @ngdoc method
8044    * @name $compileProvider#aHrefSanitizationWhitelist
8045    * @kind function
8046    *
8047    * @description
8048    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
8049    * urls during a[href] sanitization.
8050    *
8051    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
8052    *
8053    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
8054    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
8055    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
8056    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
8057    *
8058    * @param {RegExp=} regexp New regexp to whitelist urls with.
8059    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
8060    *    chaining otherwise.
8061    */
8062   this.aHrefSanitizationWhitelist = function(regexp) {
8063     if (isDefined(regexp)) {
8064       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
8065       return this;
8066     } else {
8067       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
8068     }
8069   };
8070
8071
8072   /**
8073    * @ngdoc method
8074    * @name $compileProvider#imgSrcSanitizationWhitelist
8075    * @kind function
8076    *
8077    * @description
8078    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
8079    * urls during img[src] sanitization.
8080    *
8081    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
8082    *
8083    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
8084    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
8085    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
8086    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
8087    *
8088    * @param {RegExp=} regexp New regexp to whitelist urls with.
8089    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
8090    *    chaining otherwise.
8091    */
8092   this.imgSrcSanitizationWhitelist = function(regexp) {
8093     if (isDefined(regexp)) {
8094       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
8095       return this;
8096     } else {
8097       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
8098     }
8099   };
8100
8101   /**
8102    * @ngdoc method
8103    * @name  $compileProvider#debugInfoEnabled
8104    *
8105    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
8106    * current debugInfoEnabled state
8107    * @returns {*} current value if used as getter or itself (chaining) if used as setter
8108    *
8109    * @kind function
8110    *
8111    * @description
8112    * Call this method to enable/disable various debug runtime information in the compiler such as adding
8113    * binding information and a reference to the current scope on to DOM elements.
8114    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
8115    * * `ng-binding` CSS class
8116    * * `$binding` data property containing an array of the binding expressions
8117    *
8118    * You may want to disable this in production for a significant performance boost. See
8119    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
8120    *
8121    * The default value is true.
8122    */
8123   var debugInfoEnabled = true;
8124   this.debugInfoEnabled = function(enabled) {
8125     if (isDefined(enabled)) {
8126       debugInfoEnabled = enabled;
8127       return this;
8128     }
8129     return debugInfoEnabled;
8130   };
8131
8132   /**
8133    * @ngdoc method
8134    * @name  $compileProvider#preAssignBindingsEnabled
8135    *
8136    * @param {boolean=} enabled update the preAssignBindingsEnabled state if provided, otherwise just return the
8137    * current preAssignBindingsEnabled state
8138    * @returns {*} current value if used as getter or itself (chaining) if used as setter
8139    *
8140    * @kind function
8141    *
8142    * @description
8143    * Call this method to enable/disable whether directive controllers are assigned bindings before
8144    * calling the controller's constructor.
8145    * If enabled (true), the compiler assigns the value of each of the bindings to the
8146    * properties of the controller object before the constructor of this object is called.
8147    *
8148    * If disabled (false), the compiler calls the constructor first before assigning bindings.
8149    *
8150    * The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.
8151    */
8152   var preAssignBindingsEnabled = true;
8153   this.preAssignBindingsEnabled = function(enabled) {
8154     if (isDefined(enabled)) {
8155       preAssignBindingsEnabled = enabled;
8156       return this;
8157     }
8158     return preAssignBindingsEnabled;
8159   };
8160
8161
8162   var TTL = 10;
8163   /**
8164    * @ngdoc method
8165    * @name $compileProvider#onChangesTtl
8166    * @description
8167    *
8168    * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and
8169    * assuming that the model is unstable.
8170    *
8171    * The current default is 10 iterations.
8172    *
8173    * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result
8174    * in several iterations of calls to these hooks. However if an application needs more than the default 10
8175    * iterations to stabilize then you should investigate what is causing the model to continuously change during
8176    * the `$onChanges` hook execution.
8177    *
8178    * Increasing the TTL could have performance implications, so you should not change it without proper justification.
8179    *
8180    * @param {number} limit The number of `$onChanges` hook iterations.
8181    * @returns {number|object} the current limit (or `this` if called as a setter for chaining)
8182    */
8183   this.onChangesTtl = function(value) {
8184     if (arguments.length) {
8185       TTL = value;
8186       return this;
8187     }
8188     return TTL;
8189   };
8190
8191   var commentDirectivesEnabledConfig = true;
8192   /**
8193    * @ngdoc method
8194    * @name $compileProvider#commentDirectivesEnabled
8195    * @description
8196    *
8197    * It indicates to the compiler
8198    * whether or not directives on comments should be compiled.
8199    * Defaults to `true`.
8200    *
8201    * Calling this function with false disables the compilation of directives
8202    * on comments for the whole application.
8203    * This results in a compilation performance gain,
8204    * as the compiler doesn't have to check comments when looking for directives.
8205    * This should however only be used if you are sure that no comment directives are used in
8206    * the application (including any 3rd party directives).
8207    *
8208    * @param {boolean} enabled `false` if the compiler may ignore directives on comments
8209    * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
8210    */
8211   this.commentDirectivesEnabled = function(value) {
8212     if (arguments.length) {
8213       commentDirectivesEnabledConfig = value;
8214       return this;
8215     }
8216     return commentDirectivesEnabledConfig;
8217   };
8218
8219
8220   var cssClassDirectivesEnabledConfig = true;
8221   /**
8222    * @ngdoc method
8223    * @name $compileProvider#cssClassDirectivesEnabled
8224    * @description
8225    *
8226    * It indicates to the compiler
8227    * whether or not directives on element classes should be compiled.
8228    * Defaults to `true`.
8229    *
8230    * Calling this function with false disables the compilation of directives
8231    * on element classes for the whole application.
8232    * This results in a compilation performance gain,
8233    * as the compiler doesn't have to check element classes when looking for directives.
8234    * This should however only be used if you are sure that no class directives are used in
8235    * the application (including any 3rd party directives).
8236    *
8237    * @param {boolean} enabled `false` if the compiler may ignore directives on element classes
8238    * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
8239    */
8240   this.cssClassDirectivesEnabled = function(value) {
8241     if (arguments.length) {
8242       cssClassDirectivesEnabledConfig = value;
8243       return this;
8244     }
8245     return cssClassDirectivesEnabledConfig;
8246   };
8247
8248   this.$get = [
8249             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
8250             '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
8251     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
8252              $controller,   $rootScope,   $sce,   $animate,   $$sanitizeUri) {
8253
8254     var SIMPLE_ATTR_NAME = /^\w/;
8255     var specialAttrHolder = window.document.createElement('div');
8256
8257
8258     var commentDirectivesEnabled = commentDirectivesEnabledConfig;
8259     var cssClassDirectivesEnabled = cssClassDirectivesEnabledConfig;
8260
8261
8262     var onChangesTtl = TTL;
8263     // The onChanges hooks should all be run together in a single digest
8264     // When changes occur, the call to trigger their hooks will be added to this queue
8265     var onChangesQueue;
8266
8267     // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
8268     function flushOnChangesQueue() {
8269       try {
8270         if (!(--onChangesTtl)) {
8271           // We have hit the TTL limit so reset everything
8272           onChangesQueue = undefined;
8273           throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
8274         }
8275         // We must run this hook in an apply since the $$postDigest runs outside apply
8276         $rootScope.$apply(function() {
8277           var errors = [];
8278           for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
8279             try {
8280               onChangesQueue[i]();
8281             } catch (e) {
8282               errors.push(e);
8283             }
8284           }
8285           // Reset the queue to trigger a new schedule next time there is a change
8286           onChangesQueue = undefined;
8287           if (errors.length) {
8288             throw errors;
8289           }
8290         });
8291       } finally {
8292         onChangesTtl++;
8293       }
8294     }
8295
8296
8297     function Attributes(element, attributesToCopy) {
8298       if (attributesToCopy) {
8299         var keys = Object.keys(attributesToCopy);
8300         var i, l, key;
8301
8302         for (i = 0, l = keys.length; i < l; i++) {
8303           key = keys[i];
8304           this[key] = attributesToCopy[key];
8305         }
8306       } else {
8307         this.$attr = {};
8308       }
8309
8310       this.$$element = element;
8311     }
8312
8313     Attributes.prototype = {
8314       /**
8315        * @ngdoc method
8316        * @name $compile.directive.Attributes#$normalize
8317        * @kind function
8318        *
8319        * @description
8320        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
8321        * `data-`) to its normalized, camelCase form.
8322        *
8323        * Also there is special case for Moz prefix starting with upper case letter.
8324        *
8325        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
8326        *
8327        * @param {string} name Name to normalize
8328        */
8329       $normalize: directiveNormalize,
8330
8331
8332       /**
8333        * @ngdoc method
8334        * @name $compile.directive.Attributes#$addClass
8335        * @kind function
8336        *
8337        * @description
8338        * Adds the CSS class value specified by the classVal parameter to the element. If animations
8339        * are enabled then an animation will be triggered for the class addition.
8340        *
8341        * @param {string} classVal The className value that will be added to the element
8342        */
8343       $addClass: function(classVal) {
8344         if (classVal && classVal.length > 0) {
8345           $animate.addClass(this.$$element, classVal);
8346         }
8347       },
8348
8349       /**
8350        * @ngdoc method
8351        * @name $compile.directive.Attributes#$removeClass
8352        * @kind function
8353        *
8354        * @description
8355        * Removes the CSS class value specified by the classVal parameter from the element. If
8356        * animations are enabled then an animation will be triggered for the class removal.
8357        *
8358        * @param {string} classVal The className value that will be removed from the element
8359        */
8360       $removeClass: function(classVal) {
8361         if (classVal && classVal.length > 0) {
8362           $animate.removeClass(this.$$element, classVal);
8363         }
8364       },
8365
8366       /**
8367        * @ngdoc method
8368        * @name $compile.directive.Attributes#$updateClass
8369        * @kind function
8370        *
8371        * @description
8372        * Adds and removes the appropriate CSS class values to the element based on the difference
8373        * between the new and old CSS class values (specified as newClasses and oldClasses).
8374        *
8375        * @param {string} newClasses The current CSS className value
8376        * @param {string} oldClasses The former CSS className value
8377        */
8378       $updateClass: function(newClasses, oldClasses) {
8379         var toAdd = tokenDifference(newClasses, oldClasses);
8380         if (toAdd && toAdd.length) {
8381           $animate.addClass(this.$$element, toAdd);
8382         }
8383
8384         var toRemove = tokenDifference(oldClasses, newClasses);
8385         if (toRemove && toRemove.length) {
8386           $animate.removeClass(this.$$element, toRemove);
8387         }
8388       },
8389
8390       /**
8391        * Set a normalized attribute on the element in a way such that all directives
8392        * can share the attribute. This function properly handles boolean attributes.
8393        * @param {string} key Normalized key. (ie ngAttribute)
8394        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
8395        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
8396        *     Defaults to true.
8397        * @param {string=} attrName Optional none normalized name. Defaults to key.
8398        */
8399       $set: function(key, value, writeAttr, attrName) {
8400         // TODO: decide whether or not to throw an error if "class"
8401         //is set through this function since it may cause $updateClass to
8402         //become unstable.
8403
8404         var node = this.$$element[0],
8405             booleanKey = getBooleanAttrName(node, key),
8406             aliasedKey = getAliasedAttrName(key),
8407             observer = key,
8408             nodeName;
8409
8410         if (booleanKey) {
8411           this.$$element.prop(key, value);
8412           attrName = booleanKey;
8413         } else if (aliasedKey) {
8414           this[aliasedKey] = value;
8415           observer = aliasedKey;
8416         }
8417
8418         this[key] = value;
8419
8420         // translate normalized key to actual key
8421         if (attrName) {
8422           this.$attr[key] = attrName;
8423         } else {
8424           attrName = this.$attr[key];
8425           if (!attrName) {
8426             this.$attr[key] = attrName = snake_case(key, '-');
8427           }
8428         }
8429
8430         nodeName = nodeName_(this.$$element);
8431
8432         if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
8433             (nodeName === 'img' && key === 'src')) {
8434           // sanitize a[href] and img[src] values
8435           this[key] = value = $$sanitizeUri(value, key === 'src');
8436         } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) {
8437           // sanitize img[srcset] values
8438           var result = '';
8439
8440           // first check if there are spaces because it's not the same pattern
8441           var trimmedSrcset = trim(value);
8442           //                (   999x   ,|   999w   ,|   ,|,   )
8443           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
8444           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
8445
8446           // split srcset into tuple of uri and descriptor except for the last item
8447           var rawUris = trimmedSrcset.split(pattern);
8448
8449           // for each tuples
8450           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
8451           for (var i = 0; i < nbrUrisWith2parts; i++) {
8452             var innerIdx = i * 2;
8453             // sanitize the uri
8454             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
8455             // add the descriptor
8456             result += (' ' + trim(rawUris[innerIdx + 1]));
8457           }
8458
8459           // split the last item into uri and descriptor
8460           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
8461
8462           // sanitize the last uri
8463           result += $$sanitizeUri(trim(lastTuple[0]), true);
8464
8465           // and add the last descriptor if any
8466           if (lastTuple.length === 2) {
8467             result += (' ' + trim(lastTuple[1]));
8468           }
8469           this[key] = value = result;
8470         }
8471
8472         if (writeAttr !== false) {
8473           if (value === null || isUndefined(value)) {
8474             this.$$element.removeAttr(attrName);
8475           } else {
8476             if (SIMPLE_ATTR_NAME.test(attrName)) {
8477               this.$$element.attr(attrName, value);
8478             } else {
8479               setSpecialAttr(this.$$element[0], attrName, value);
8480             }
8481           }
8482         }
8483
8484         // fire observers
8485         var $$observers = this.$$observers;
8486         if ($$observers) {
8487           forEach($$observers[observer], function(fn) {
8488             try {
8489               fn(value);
8490             } catch (e) {
8491               $exceptionHandler(e);
8492             }
8493           });
8494         }
8495       },
8496
8497
8498       /**
8499        * @ngdoc method
8500        * @name $compile.directive.Attributes#$observe
8501        * @kind function
8502        *
8503        * @description
8504        * Observes an interpolated attribute.
8505        *
8506        * The observer function will be invoked once during the next `$digest` following
8507        * compilation. The observer is then invoked whenever the interpolated value
8508        * changes.
8509        *
8510        * @param {string} key Normalized key. (ie ngAttribute) .
8511        * @param {function(interpolatedValue)} fn Function that will be called whenever
8512                 the interpolated value of the attribute changes.
8513        *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
8514        *        guide} for more info.
8515        * @returns {function()} Returns a deregistration function for this observer.
8516        */
8517       $observe: function(key, fn) {
8518         var attrs = this,
8519             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
8520             listeners = ($$observers[key] || ($$observers[key] = []));
8521
8522         listeners.push(fn);
8523         $rootScope.$evalAsync(function() {
8524           if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
8525             // no one registered attribute interpolation function, so lets call it manually
8526             fn(attrs[key]);
8527           }
8528         });
8529
8530         return function() {
8531           arrayRemove(listeners, fn);
8532         };
8533       }
8534     };
8535
8536     function setSpecialAttr(element, attrName, value) {
8537       // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
8538       // so we have to jump through some hoops to get such an attribute
8539       // https://github.com/angular/angular.js/pull/13318
8540       specialAttrHolder.innerHTML = '<span ' + attrName + '>';
8541       var attributes = specialAttrHolder.firstChild.attributes;
8542       var attribute = attributes[0];
8543       // We have to remove the attribute from its container element before we can add it to the destination element
8544       attributes.removeNamedItem(attribute.name);
8545       attribute.value = value;
8546       element.attributes.setNamedItem(attribute);
8547     }
8548
8549     function safeAddClass($element, className) {
8550       try {
8551         $element.addClass(className);
8552       } catch (e) {
8553         // ignore, since it means that we are trying to set class on
8554         // SVG element, where class name is read-only.
8555       }
8556     }
8557
8558
8559     var startSymbol = $interpolate.startSymbol(),
8560         endSymbol = $interpolate.endSymbol(),
8561         denormalizeTemplate = (startSymbol === '{{' && endSymbol  === '}}')
8562             ? identity
8563             : function denormalizeTemplate(template) {
8564               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
8565         },
8566         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
8567     var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
8568
8569     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
8570       var bindings = $element.data('$binding') || [];
8571
8572       if (isArray(binding)) {
8573         bindings = bindings.concat(binding);
8574       } else {
8575         bindings.push(binding);
8576       }
8577
8578       $element.data('$binding', bindings);
8579     } : noop;
8580
8581     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
8582       safeAddClass($element, 'ng-binding');
8583     } : noop;
8584
8585     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
8586       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
8587       $element.data(dataName, scope);
8588     } : noop;
8589
8590     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
8591       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
8592     } : noop;
8593
8594     compile.$$createComment = function(directiveName, comment) {
8595       var content = '';
8596       if (debugInfoEnabled) {
8597         content = ' ' + (directiveName || '') + ': ';
8598         if (comment) content += comment + ' ';
8599       }
8600       return window.document.createComment(content);
8601     };
8602
8603     return compile;
8604
8605     //================================
8606
8607     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
8608                         previousCompileContext) {
8609       if (!($compileNodes instanceof jqLite)) {
8610         // jquery always rewraps, whereas we need to preserve the original selector so that we can
8611         // modify it.
8612         $compileNodes = jqLite($compileNodes);
8613       }
8614
8615       var NOT_EMPTY = /\S+/;
8616
8617       // We can not compile top level text elements since text nodes can be merged and we will
8618       // not be able to attach scope data to them, so we will wrap them in <span>
8619       for (var i = 0, len = $compileNodes.length; i < len; i++) {
8620         var domNode = $compileNodes[i];
8621
8622         if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
8623           jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
8624         }
8625       }
8626
8627       var compositeLinkFn =
8628               compileNodes($compileNodes, transcludeFn, $compileNodes,
8629                            maxPriority, ignoreDirective, previousCompileContext);
8630       compile.$$addScopeClass($compileNodes);
8631       var namespace = null;
8632       return function publicLinkFn(scope, cloneConnectFn, options) {
8633         assertArg(scope, 'scope');
8634
8635         if (previousCompileContext && previousCompileContext.needsNewScope) {
8636           // A parent directive did a replace and a directive on this element asked
8637           // for transclusion, which caused us to lose a layer of element on which
8638           // we could hold the new transclusion scope, so we will create it manually
8639           // here.
8640           scope = scope.$parent.$new();
8641         }
8642
8643         options = options || {};
8644         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
8645           transcludeControllers = options.transcludeControllers,
8646           futureParentElement = options.futureParentElement;
8647
8648         // When `parentBoundTranscludeFn` is passed, it is a
8649         // `controllersBoundTransclude` function (it was previously passed
8650         // as `transclude` to directive.link) so we must unwrap it to get
8651         // its `boundTranscludeFn`
8652         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
8653           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
8654         }
8655
8656         if (!namespace) {
8657           namespace = detectNamespaceForChildElements(futureParentElement);
8658         }
8659         var $linkNode;
8660         if (namespace !== 'html') {
8661           // When using a directive with replace:true and templateUrl the $compileNodes
8662           // (or a child element inside of them)
8663           // might change, so we need to recreate the namespace adapted compileNodes
8664           // for call to the link function.
8665           // Note: This will already clone the nodes...
8666           $linkNode = jqLite(
8667             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
8668           );
8669         } else if (cloneConnectFn) {
8670           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
8671           // and sometimes changes the structure of the DOM.
8672           $linkNode = JQLitePrototype.clone.call($compileNodes);
8673         } else {
8674           $linkNode = $compileNodes;
8675         }
8676
8677         if (transcludeControllers) {
8678           for (var controllerName in transcludeControllers) {
8679             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
8680           }
8681         }
8682
8683         compile.$$addScopeInfo($linkNode, scope);
8684
8685         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
8686         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
8687         return $linkNode;
8688       };
8689     }
8690
8691     function detectNamespaceForChildElements(parentElement) {
8692       // TODO: Make this detect MathML as well...
8693       var node = parentElement && parentElement[0];
8694       if (!node) {
8695         return 'html';
8696       } else {
8697         return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
8698       }
8699     }
8700
8701     /**
8702      * Compile function matches each node in nodeList against the directives. Once all directives
8703      * for a particular node are collected their compile functions are executed. The compile
8704      * functions return values - the linking functions - are combined into a composite linking
8705      * function, which is the a linking function for the node.
8706      *
8707      * @param {NodeList} nodeList an array of nodes or NodeList to compile
8708      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
8709      *        scope argument is auto-generated to the new child of the transcluded parent scope.
8710      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
8711      *        the rootElement must be set the jqLite collection of the compile root. This is
8712      *        needed so that the jqLite collection items can be replaced with widgets.
8713      * @param {number=} maxPriority Max directive priority.
8714      * @returns {Function} A composite linking function of all of the matched directives or null.
8715      */
8716     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
8717                             previousCompileContext) {
8718       var linkFns = [],
8719           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
8720
8721       for (var i = 0; i < nodeList.length; i++) {
8722         attrs = new Attributes();
8723
8724         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
8725         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
8726                                         ignoreDirective);
8727
8728         nodeLinkFn = (directives.length)
8729             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
8730                                       null, [], [], previousCompileContext)
8731             : null;
8732
8733         if (nodeLinkFn && nodeLinkFn.scope) {
8734           compile.$$addScopeClass(attrs.$$element);
8735         }
8736
8737         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
8738                       !(childNodes = nodeList[i].childNodes) ||
8739                       !childNodes.length)
8740             ? null
8741             : compileNodes(childNodes,
8742                  nodeLinkFn ? (
8743                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
8744                      && nodeLinkFn.transclude) : transcludeFn);
8745
8746         if (nodeLinkFn || childLinkFn) {
8747           linkFns.push(i, nodeLinkFn, childLinkFn);
8748           linkFnFound = true;
8749           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
8750         }
8751
8752         //use the previous context only for the first element in the virtual group
8753         previousCompileContext = null;
8754       }
8755
8756       // return a linking function if we have found anything, null otherwise
8757       return linkFnFound ? compositeLinkFn : null;
8758
8759       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
8760         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
8761         var stableNodeList;
8762
8763
8764         if (nodeLinkFnFound) {
8765           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
8766           // offsets don't get screwed up
8767           var nodeListLength = nodeList.length;
8768           stableNodeList = new Array(nodeListLength);
8769
8770           // create a sparse array by only copying the elements which have a linkFn
8771           for (i = 0; i < linkFns.length; i += 3) {
8772             idx = linkFns[i];
8773             stableNodeList[idx] = nodeList[idx];
8774           }
8775         } else {
8776           stableNodeList = nodeList;
8777         }
8778
8779         for (i = 0, ii = linkFns.length; i < ii;) {
8780           node = stableNodeList[linkFns[i++]];
8781           nodeLinkFn = linkFns[i++];
8782           childLinkFn = linkFns[i++];
8783
8784           if (nodeLinkFn) {
8785             if (nodeLinkFn.scope) {
8786               childScope = scope.$new();
8787               compile.$$addScopeInfo(jqLite(node), childScope);
8788             } else {
8789               childScope = scope;
8790             }
8791
8792             if (nodeLinkFn.transcludeOnThisElement) {
8793               childBoundTranscludeFn = createBoundTranscludeFn(
8794                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
8795
8796             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
8797               childBoundTranscludeFn = parentBoundTranscludeFn;
8798
8799             } else if (!parentBoundTranscludeFn && transcludeFn) {
8800               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
8801
8802             } else {
8803               childBoundTranscludeFn = null;
8804             }
8805
8806             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
8807
8808           } else if (childLinkFn) {
8809             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
8810           }
8811         }
8812       }
8813     }
8814
8815     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
8816       function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
8817
8818         if (!transcludedScope) {
8819           transcludedScope = scope.$new(false, containingScope);
8820           transcludedScope.$$transcluded = true;
8821         }
8822
8823         return transcludeFn(transcludedScope, cloneFn, {
8824           parentBoundTranscludeFn: previousBoundTranscludeFn,
8825           transcludeControllers: controllers,
8826           futureParentElement: futureParentElement
8827         });
8828       }
8829
8830       // We need  to attach the transclusion slots onto the `boundTranscludeFn`
8831       // so that they are available inside the `controllersBoundTransclude` function
8832       var boundSlots = boundTranscludeFn.$$slots = createMap();
8833       for (var slotName in transcludeFn.$$slots) {
8834         if (transcludeFn.$$slots[slotName]) {
8835           boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
8836         } else {
8837           boundSlots[slotName] = null;
8838         }
8839       }
8840
8841       return boundTranscludeFn;
8842     }
8843
8844     /**
8845      * Looks for directives on the given node and adds them to the directive collection which is
8846      * sorted.
8847      *
8848      * @param node Node to search.
8849      * @param directives An array to which the directives are added to. This array is sorted before
8850      *        the function returns.
8851      * @param attrs The shared attrs object which is used to populate the normalized attributes.
8852      * @param {number=} maxPriority Max directive priority.
8853      */
8854     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
8855       var nodeType = node.nodeType,
8856           attrsMap = attrs.$attr,
8857           match,
8858           nodeName,
8859           className;
8860
8861       switch (nodeType) {
8862         case NODE_TYPE_ELEMENT: /* Element */
8863
8864           nodeName = nodeName_(node);
8865
8866           // use the node name: <directive>
8867           addDirective(directives,
8868               directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
8869
8870           // iterate over the attributes
8871           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
8872                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
8873             var attrStartName = false;
8874             var attrEndName = false;
8875
8876             attr = nAttrs[j];
8877             name = attr.name;
8878             value = trim(attr.value);
8879
8880             // support ngAttr attribute binding
8881             ngAttrName = directiveNormalize(name);
8882             isNgAttr = NG_ATTR_BINDING.test(ngAttrName);
8883             if (isNgAttr) {
8884               name = name.replace(PREFIX_REGEXP, '')
8885                 .substr(8).replace(/_(.)/g, function(match, letter) {
8886                   return letter.toUpperCase();
8887                 });
8888             }
8889
8890             var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
8891             if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
8892               attrStartName = name;
8893               attrEndName = name.substr(0, name.length - 5) + 'end';
8894               name = name.substr(0, name.length - 6);
8895             }
8896
8897             nName = directiveNormalize(name.toLowerCase());
8898             attrsMap[nName] = name;
8899             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
8900                 attrs[nName] = value;
8901                 if (getBooleanAttrName(node, nName)) {
8902                   attrs[nName] = true; // presence means true
8903                 }
8904             }
8905             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
8906             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
8907                           attrEndName);
8908           }
8909
8910           if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
8911             // Hidden input elements can have strange behaviour when navigating back to the page
8912             // This tells the browser not to try to cache and reinstate previous values
8913             node.setAttribute('autocomplete', 'off');
8914           }
8915
8916           // use class as directive
8917           if (!cssClassDirectivesEnabled) break;
8918           className = node.className;
8919           if (isObject(className)) {
8920               // Maybe SVGAnimatedString
8921               className = className.animVal;
8922           }
8923           if (isString(className) && className !== '') {
8924             while ((match = CLASS_DIRECTIVE_REGEXP.exec(className))) {
8925               nName = directiveNormalize(match[2]);
8926               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
8927                 attrs[nName] = trim(match[3]);
8928               }
8929               className = className.substr(match.index + match[0].length);
8930             }
8931           }
8932           break;
8933         case NODE_TYPE_TEXT: /* Text Node */
8934           if (msie === 11) {
8935             // Workaround for #11781
8936             while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
8937               node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
8938               node.parentNode.removeChild(node.nextSibling);
8939             }
8940           }
8941           addTextInterpolateDirective(directives, node.nodeValue);
8942           break;
8943         case NODE_TYPE_COMMENT: /* Comment */
8944           if (!commentDirectivesEnabled) break;
8945           collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);
8946           break;
8947       }
8948
8949       directives.sort(byPriority);
8950       return directives;
8951     }
8952
8953     function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
8954       // function created because of performance, try/catch disables
8955       // the optimization of the whole function #14848
8956       try {
8957         var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
8958         if (match) {
8959           var nName = directiveNormalize(match[1]);
8960           if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
8961             attrs[nName] = trim(match[2]);
8962           }
8963         }
8964       } catch (e) {
8965         // turns out that under some circumstances IE9 throws errors when one attempts to read
8966         // comment's node value.
8967         // Just ignore it and continue. (Can't seem to reproduce in test case.)
8968       }
8969     }
8970
8971     /**
8972      * Given a node with a directive-start it collects all of the siblings until it finds
8973      * directive-end.
8974      * @param node
8975      * @param attrStart
8976      * @param attrEnd
8977      * @returns {*}
8978      */
8979     function groupScan(node, attrStart, attrEnd) {
8980       var nodes = [];
8981       var depth = 0;
8982       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
8983         do {
8984           if (!node) {
8985             throw $compileMinErr('uterdir',
8986                       'Unterminated attribute, found \'{0}\' but no matching \'{1}\' found.',
8987                       attrStart, attrEnd);
8988           }
8989           if (node.nodeType === NODE_TYPE_ELEMENT) {
8990             if (node.hasAttribute(attrStart)) depth++;
8991             if (node.hasAttribute(attrEnd)) depth--;
8992           }
8993           nodes.push(node);
8994           node = node.nextSibling;
8995         } while (depth > 0);
8996       } else {
8997         nodes.push(node);
8998       }
8999
9000       return jqLite(nodes);
9001     }
9002
9003     /**
9004      * Wrapper for linking function which converts normal linking function into a grouped
9005      * linking function.
9006      * @param linkFn
9007      * @param attrStart
9008      * @param attrEnd
9009      * @returns {Function}
9010      */
9011     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
9012       return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
9013         element = groupScan(element[0], attrStart, attrEnd);
9014         return linkFn(scope, element, attrs, controllers, transcludeFn);
9015       };
9016     }
9017
9018     /**
9019      * A function generator that is used to support both eager and lazy compilation
9020      * linking function.
9021      * @param eager
9022      * @param $compileNodes
9023      * @param transcludeFn
9024      * @param maxPriority
9025      * @param ignoreDirective
9026      * @param previousCompileContext
9027      * @returns {Function}
9028      */
9029     function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
9030       var compiled;
9031
9032       if (eager) {
9033         return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
9034       }
9035       return /** @this */ function lazyCompilation() {
9036         if (!compiled) {
9037           compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
9038
9039           // Null out all of these references in order to make them eligible for garbage collection
9040           // since this is a potentially long lived closure
9041           $compileNodes = transcludeFn = previousCompileContext = null;
9042         }
9043         return compiled.apply(this, arguments);
9044       };
9045     }
9046
9047     /**
9048      * Once the directives have been collected, their compile functions are executed. This method
9049      * is responsible for inlining directive templates as well as terminating the application
9050      * of the directives if the terminal directive has been reached.
9051      *
9052      * @param {Array} directives Array of collected directives to execute their compile function.
9053      *        this needs to be pre-sorted by priority order.
9054      * @param {Node} compileNode The raw DOM node to apply the compile functions to
9055      * @param {Object} templateAttrs The shared attribute function
9056      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
9057      *                                                  scope argument is auto-generated to the new
9058      *                                                  child of the transcluded parent scope.
9059      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
9060      *                              argument has the root jqLite array so that we can replace nodes
9061      *                              on it.
9062      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
9063      *                                           compiling the transclusion.
9064      * @param {Array.<Function>} preLinkFns
9065      * @param {Array.<Function>} postLinkFns
9066      * @param {Object} previousCompileContext Context used for previous compilation of the current
9067      *                                        node
9068      * @returns {Function} linkFn
9069      */
9070     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
9071                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
9072                                    previousCompileContext) {
9073       previousCompileContext = previousCompileContext || {};
9074
9075       var terminalPriority = -Number.MAX_VALUE,
9076           newScopeDirective = previousCompileContext.newScopeDirective,
9077           controllerDirectives = previousCompileContext.controllerDirectives,
9078           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
9079           templateDirective = previousCompileContext.templateDirective,
9080           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
9081           hasTranscludeDirective = false,
9082           hasTemplate = false,
9083           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
9084           $compileNode = templateAttrs.$$element = jqLite(compileNode),
9085           directive,
9086           directiveName,
9087           $template,
9088           replaceDirective = originalReplaceDirective,
9089           childTranscludeFn = transcludeFn,
9090           linkFn,
9091           didScanForMultipleTransclusion = false,
9092           mightHaveMultipleTransclusionError = false,
9093           directiveValue;
9094
9095       // executes all directives on the current element
9096       for (var i = 0, ii = directives.length; i < ii; i++) {
9097         directive = directives[i];
9098         var attrStart = directive.$$start;
9099         var attrEnd = directive.$$end;
9100
9101         // collect multiblock sections
9102         if (attrStart) {
9103           $compileNode = groupScan(compileNode, attrStart, attrEnd);
9104         }
9105         $template = undefined;
9106
9107         if (terminalPriority > directive.priority) {
9108           break; // prevent further processing of directives
9109         }
9110
9111         directiveValue = directive.scope;
9112
9113         if (directiveValue) {
9114
9115           // skip the check for directives with async templates, we'll check the derived sync
9116           // directive when the template arrives
9117           if (!directive.templateUrl) {
9118             if (isObject(directiveValue)) {
9119               // This directive is trying to add an isolated scope.
9120               // Check that there is no scope of any kind already
9121               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
9122                                 directive, $compileNode);
9123               newIsolateScopeDirective = directive;
9124             } else {
9125               // This directive is trying to add a child scope.
9126               // Check that there is no isolated scope already
9127               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
9128                                 $compileNode);
9129             }
9130           }
9131
9132           newScopeDirective = newScopeDirective || directive;
9133         }
9134
9135         directiveName = directive.name;
9136
9137         // If we encounter a condition that can result in transclusion on the directive,
9138         // then scan ahead in the remaining directives for others that may cause a multiple
9139         // transclusion error to be thrown during the compilation process.  If a matching directive
9140         // is found, then we know that when we encounter a transcluded directive, we need to eagerly
9141         // compile the `transclude` function rather than doing it lazily in order to throw
9142         // exceptions at the correct time
9143         if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
9144             || (directive.transclude && !directive.$$tlb))) {
9145                 var candidateDirective;
9146
9147                 for (var scanningIndex = i + 1; (candidateDirective = directives[scanningIndex++]);) {
9148                     if ((candidateDirective.transclude && !candidateDirective.$$tlb)
9149                         || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
9150                         mightHaveMultipleTransclusionError = true;
9151                         break;
9152                     }
9153                 }
9154
9155                 didScanForMultipleTransclusion = true;
9156         }
9157
9158         if (!directive.templateUrl && directive.controller) {
9159           controllerDirectives = controllerDirectives || createMap();
9160           assertNoDuplicate('\'' + directiveName + '\' controller',
9161               controllerDirectives[directiveName], directive, $compileNode);
9162           controllerDirectives[directiveName] = directive;
9163         }
9164
9165         directiveValue = directive.transclude;
9166
9167         if (directiveValue) {
9168           hasTranscludeDirective = true;
9169
9170           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
9171           // This option should only be used by directives that know how to safely handle element transclusion,
9172           // where the transcluded nodes are added or replaced after linking.
9173           if (!directive.$$tlb) {
9174             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
9175             nonTlbTranscludeDirective = directive;
9176           }
9177
9178           if (directiveValue === 'element') {
9179             hasElementTranscludeDirective = true;
9180             terminalPriority = directive.priority;
9181             $template = $compileNode;
9182             $compileNode = templateAttrs.$$element =
9183                 jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
9184             compileNode = $compileNode[0];
9185             replaceWith(jqCollection, sliceArgs($template), compileNode);
9186
9187             // Support: Chrome < 50
9188             // https://github.com/angular/angular.js/issues/14041
9189
9190             // In the versions of V8 prior to Chrome 50, the document fragment that is created
9191             // in the `replaceWith` function is improperly garbage collected despite still
9192             // being referenced by the `parentNode` property of all of the child nodes.  By adding
9193             // a reference to the fragment via a different property, we can avoid that incorrect
9194             // behavior.
9195             // TODO: remove this line after Chrome 50 has been released
9196             $template[0].$$parentNode = $template[0].parentNode;
9197
9198             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
9199                                         replaceDirective && replaceDirective.name, {
9200                                           // Don't pass in:
9201                                           // - controllerDirectives - otherwise we'll create duplicates controllers
9202                                           // - newIsolateScopeDirective or templateDirective - combining templates with
9203                                           //   element transclusion doesn't make sense.
9204                                           //
9205                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
9206                                           // on the same element more than once.
9207                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
9208                                         });
9209           } else {
9210
9211             var slots = createMap();
9212
9213             $template = jqLite(jqLiteClone(compileNode)).contents();
9214
9215             if (isObject(directiveValue)) {
9216
9217               // We have transclusion slots,
9218               // collect them up, compile them and store their transclusion functions
9219               $template = [];
9220
9221               var slotMap = createMap();
9222               var filledSlots = createMap();
9223
9224               // Parse the element selectors
9225               forEach(directiveValue, function(elementSelector, slotName) {
9226                 // If an element selector starts with a ? then it is optional
9227                 var optional = (elementSelector.charAt(0) === '?');
9228                 elementSelector = optional ? elementSelector.substring(1) : elementSelector;
9229
9230                 slotMap[elementSelector] = slotName;
9231
9232                 // We explicitly assign `null` since this implies that a slot was defined but not filled.
9233                 // Later when calling boundTransclusion functions with a slot name we only error if the
9234                 // slot is `undefined`
9235                 slots[slotName] = null;
9236
9237                 // filledSlots contains `true` for all slots that are either optional or have been
9238                 // filled. This is used to check that we have not missed any required slots
9239                 filledSlots[slotName] = optional;
9240               });
9241
9242               // Add the matching elements into their slot
9243               forEach($compileNode.contents(), function(node) {
9244                 var slotName = slotMap[directiveNormalize(nodeName_(node))];
9245                 if (slotName) {
9246                   filledSlots[slotName] = true;
9247                   slots[slotName] = slots[slotName] || [];
9248                   slots[slotName].push(node);
9249                 } else {
9250                   $template.push(node);
9251                 }
9252               });
9253
9254               // Check for required slots that were not filled
9255               forEach(filledSlots, function(filled, slotName) {
9256                 if (!filled) {
9257                   throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
9258                 }
9259               });
9260
9261               for (var slotName in slots) {
9262                 if (slots[slotName]) {
9263                   // Only define a transclusion function if the slot was filled
9264                   slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
9265                 }
9266               }
9267             }
9268
9269             $compileNode.empty(); // clear contents
9270             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
9271                 undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
9272             childTranscludeFn.$$slots = slots;
9273           }
9274         }
9275
9276         if (directive.template) {
9277           hasTemplate = true;
9278           assertNoDuplicate('template', templateDirective, directive, $compileNode);
9279           templateDirective = directive;
9280
9281           directiveValue = (isFunction(directive.template))
9282               ? directive.template($compileNode, templateAttrs)
9283               : directive.template;
9284
9285           directiveValue = denormalizeTemplate(directiveValue);
9286
9287           if (directive.replace) {
9288             replaceDirective = directive;
9289             if (jqLiteIsTextNode(directiveValue)) {
9290               $template = [];
9291             } else {
9292               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
9293             }
9294             compileNode = $template[0];
9295
9296             if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
9297               throw $compileMinErr('tplrt',
9298                   'Template for directive \'{0}\' must have exactly one root element. {1}',
9299                   directiveName, '');
9300             }
9301
9302             replaceWith(jqCollection, $compileNode, compileNode);
9303
9304             var newTemplateAttrs = {$attr: {}};
9305
9306             // combine directives from the original node and from the template:
9307             // - take the array of directives for this element
9308             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
9309             // - collect directives from the template and sort them by priority
9310             // - combine directives as: processed + template + unprocessed
9311             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
9312             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
9313
9314             if (newIsolateScopeDirective || newScopeDirective) {
9315               // The original directive caused the current element to be replaced but this element
9316               // also needs to have a new scope, so we need to tell the template directives
9317               // that they would need to get their scope from further up, if they require transclusion
9318               markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
9319             }
9320             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
9321             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
9322
9323             ii = directives.length;
9324           } else {
9325             $compileNode.html(directiveValue);
9326           }
9327         }
9328
9329         if (directive.templateUrl) {
9330           hasTemplate = true;
9331           assertNoDuplicate('template', templateDirective, directive, $compileNode);
9332           templateDirective = directive;
9333
9334           if (directive.replace) {
9335             replaceDirective = directive;
9336           }
9337
9338           // eslint-disable-next-line no-func-assign
9339           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
9340               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
9341                 controllerDirectives: controllerDirectives,
9342                 newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
9343                 newIsolateScopeDirective: newIsolateScopeDirective,
9344                 templateDirective: templateDirective,
9345                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
9346               });
9347           ii = directives.length;
9348         } else if (directive.compile) {
9349           try {
9350             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
9351             var context = directive.$$originalDirective || directive;
9352             if (isFunction(linkFn)) {
9353               addLinkFns(null, bind(context, linkFn), attrStart, attrEnd);
9354             } else if (linkFn) {
9355               addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd);
9356             }
9357           } catch (e) {
9358             $exceptionHandler(e, startingTag($compileNode));
9359           }
9360         }
9361
9362         if (directive.terminal) {
9363           nodeLinkFn.terminal = true;
9364           terminalPriority = Math.max(terminalPriority, directive.priority);
9365         }
9366
9367       }
9368
9369       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
9370       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
9371       nodeLinkFn.templateOnThisElement = hasTemplate;
9372       nodeLinkFn.transclude = childTranscludeFn;
9373
9374       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
9375
9376       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
9377       return nodeLinkFn;
9378
9379       ////////////////////
9380
9381       function addLinkFns(pre, post, attrStart, attrEnd) {
9382         if (pre) {
9383           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
9384           pre.require = directive.require;
9385           pre.directiveName = directiveName;
9386           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
9387             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
9388           }
9389           preLinkFns.push(pre);
9390         }
9391         if (post) {
9392           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
9393           post.require = directive.require;
9394           post.directiveName = directiveName;
9395           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
9396             post = cloneAndAnnotateFn(post, {isolateScope: true});
9397           }
9398           postLinkFns.push(post);
9399         }
9400       }
9401
9402       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
9403         var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
9404             attrs, scopeBindingInfo;
9405
9406         if (compileNode === linkNode) {
9407           attrs = templateAttrs;
9408           $element = templateAttrs.$$element;
9409         } else {
9410           $element = jqLite(linkNode);
9411           attrs = new Attributes($element, templateAttrs);
9412         }
9413
9414         controllerScope = scope;
9415         if (newIsolateScopeDirective) {
9416           isolateScope = scope.$new(true);
9417         } else if (newScopeDirective) {
9418           controllerScope = scope.$parent;
9419         }
9420
9421         if (boundTranscludeFn) {
9422           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
9423           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
9424           transcludeFn = controllersBoundTransclude;
9425           transcludeFn.$$boundTransclude = boundTranscludeFn;
9426           // expose the slots on the `$transclude` function
9427           transcludeFn.isSlotFilled = function(slotName) {
9428             return !!boundTranscludeFn.$$slots[slotName];
9429           };
9430         }
9431
9432         if (controllerDirectives) {
9433           elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
9434         }
9435
9436         if (newIsolateScopeDirective) {
9437           // Initialize isolate scope bindings for new isolate scope directive.
9438           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
9439               templateDirective === newIsolateScopeDirective.$$originalDirective)));
9440           compile.$$addScopeClass($element, true);
9441           isolateScope.$$isolateBindings =
9442               newIsolateScopeDirective.$$isolateBindings;
9443           scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
9444                                         isolateScope.$$isolateBindings,
9445                                         newIsolateScopeDirective);
9446           if (scopeBindingInfo.removeWatches) {
9447             isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
9448           }
9449         }
9450
9451         // Initialize bindToController bindings
9452         for (var name in elementControllers) {
9453           var controllerDirective = controllerDirectives[name];
9454           var controller = elementControllers[name];
9455           var bindings = controllerDirective.$$bindings.bindToController;
9456
9457           if (preAssignBindingsEnabled) {
9458             if (bindings) {
9459               controller.bindingInfo =
9460                 initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
9461             } else {
9462               controller.bindingInfo = {};
9463             }
9464
9465             var controllerResult = controller();
9466             if (controllerResult !== controller.instance) {
9467               // If the controller constructor has a return value, overwrite the instance
9468               // from setupControllers
9469               controller.instance = controllerResult;
9470               $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
9471               if (controller.bindingInfo.removeWatches) {
9472                 controller.bindingInfo.removeWatches();
9473               }
9474               controller.bindingInfo =
9475                 initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
9476             }
9477           } else {
9478             controller.instance = controller();
9479             $element.data('$' + controllerDirective.name + 'Controller', controller.instance);
9480             controller.bindingInfo =
9481               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
9482           }
9483         }
9484
9485         // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
9486         forEach(controllerDirectives, function(controllerDirective, name) {
9487           var require = controllerDirective.require;
9488           if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
9489             extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
9490           }
9491         });
9492
9493         // Handle the init and destroy lifecycle hooks on all controllers that have them
9494         forEach(elementControllers, function(controller) {
9495           var controllerInstance = controller.instance;
9496           if (isFunction(controllerInstance.$onChanges)) {
9497             try {
9498               controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
9499             } catch (e) {
9500               $exceptionHandler(e);
9501             }
9502           }
9503           if (isFunction(controllerInstance.$onInit)) {
9504             try {
9505               controllerInstance.$onInit();
9506             } catch (e) {
9507               $exceptionHandler(e);
9508             }
9509           }
9510           if (isFunction(controllerInstance.$doCheck)) {
9511             controllerScope.$watch(function() { controllerInstance.$doCheck(); });
9512             controllerInstance.$doCheck();
9513           }
9514           if (isFunction(controllerInstance.$onDestroy)) {
9515             controllerScope.$on('$destroy', function callOnDestroyHook() {
9516               controllerInstance.$onDestroy();
9517             });
9518           }
9519         });
9520
9521         // PRELINKING
9522         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
9523           linkFn = preLinkFns[i];
9524           invokeLinkFn(linkFn,
9525               linkFn.isolateScope ? isolateScope : scope,
9526               $element,
9527               attrs,
9528               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
9529               transcludeFn
9530           );
9531         }
9532
9533         // RECURSION
9534         // We only pass the isolate scope, if the isolate directive has a template,
9535         // otherwise the child elements do not belong to the isolate directive.
9536         var scopeToChild = scope;
9537         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
9538           scopeToChild = isolateScope;
9539         }
9540         if (childLinkFn) {
9541           childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
9542         }
9543
9544         // POSTLINKING
9545         for (i = postLinkFns.length - 1; i >= 0; i--) {
9546           linkFn = postLinkFns[i];
9547           invokeLinkFn(linkFn,
9548               linkFn.isolateScope ? isolateScope : scope,
9549               $element,
9550               attrs,
9551               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
9552               transcludeFn
9553           );
9554         }
9555
9556         // Trigger $postLink lifecycle hooks
9557         forEach(elementControllers, function(controller) {
9558           var controllerInstance = controller.instance;
9559           if (isFunction(controllerInstance.$postLink)) {
9560             controllerInstance.$postLink();
9561           }
9562         });
9563
9564         // This is the function that is injected as `$transclude`.
9565         // Note: all arguments are optional!
9566         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
9567           var transcludeControllers;
9568           // No scope passed in:
9569           if (!isScope(scope)) {
9570             slotName = futureParentElement;
9571             futureParentElement = cloneAttachFn;
9572             cloneAttachFn = scope;
9573             scope = undefined;
9574           }
9575
9576           if (hasElementTranscludeDirective) {
9577             transcludeControllers = elementControllers;
9578           }
9579           if (!futureParentElement) {
9580             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
9581           }
9582           if (slotName) {
9583             // slotTranscludeFn can be one of three things:
9584             //  * a transclude function - a filled slot
9585             //  * `null` - an optional slot that was not filled
9586             //  * `undefined` - a slot that was not declared (i.e. invalid)
9587             var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
9588             if (slotTranscludeFn) {
9589               return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
9590             } else if (isUndefined(slotTranscludeFn)) {
9591               throw $compileMinErr('noslot',
9592                'No parent directive that requires a transclusion with slot name "{0}". ' +
9593                'Element: {1}',
9594                slotName, startingTag($element));
9595             }
9596           } else {
9597             return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
9598           }
9599         }
9600       }
9601     }
9602
9603     function getControllers(directiveName, require, $element, elementControllers) {
9604       var value;
9605
9606       if (isString(require)) {
9607         var match = require.match(REQUIRE_PREFIX_REGEXP);
9608         var name = require.substring(match[0].length);
9609         var inheritType = match[1] || match[3];
9610         var optional = match[2] === '?';
9611
9612         //If only parents then start at the parent element
9613         if (inheritType === '^^') {
9614           $element = $element.parent();
9615         //Otherwise attempt getting the controller from elementControllers in case
9616         //the element is transcluded (and has no data) and to avoid .data if possible
9617         } else {
9618           value = elementControllers && elementControllers[name];
9619           value = value && value.instance;
9620         }
9621
9622         if (!value) {
9623           var dataName = '$' + name + 'Controller';
9624           value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
9625         }
9626
9627         if (!value && !optional) {
9628           throw $compileMinErr('ctreq',
9629               'Controller \'{0}\', required by directive \'{1}\', can\'t be found!',
9630               name, directiveName);
9631         }
9632       } else if (isArray(require)) {
9633         value = [];
9634         for (var i = 0, ii = require.length; i < ii; i++) {
9635           value[i] = getControllers(directiveName, require[i], $element, elementControllers);
9636         }
9637       } else if (isObject(require)) {
9638         value = {};
9639         forEach(require, function(controller, property) {
9640           value[property] = getControllers(directiveName, controller, $element, elementControllers);
9641         });
9642       }
9643
9644       return value || null;
9645     }
9646
9647     function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
9648       var elementControllers = createMap();
9649       for (var controllerKey in controllerDirectives) {
9650         var directive = controllerDirectives[controllerKey];
9651         var locals = {
9652           $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
9653           $element: $element,
9654           $attrs: attrs,
9655           $transclude: transcludeFn
9656         };
9657
9658         var controller = directive.controller;
9659         if (controller === '@') {
9660           controller = attrs[directive.name];
9661         }
9662
9663         var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
9664
9665         // For directives with element transclusion the element is a comment.
9666         // In this case .data will not attach any data.
9667         // Instead, we save the controllers for the element in a local hash and attach to .data
9668         // later, once we have the actual element.
9669         elementControllers[directive.name] = controllerInstance;
9670         $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
9671       }
9672       return elementControllers;
9673     }
9674
9675     // Depending upon the context in which a directive finds itself it might need to have a new isolated
9676     // or child scope created. For instance:
9677     // * if the directive has been pulled into a template because another directive with a higher priority
9678     // asked for element transclusion
9679     // * if the directive itself asks for transclusion but it is at the root of a template and the original
9680     // element was replaced. See https://github.com/angular/angular.js/issues/12936
9681     function markDirectiveScope(directives, isolateScope, newScope) {
9682       for (var j = 0, jj = directives.length; j < jj; j++) {
9683         directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
9684       }
9685     }
9686
9687     /**
9688      * looks up the directive and decorates it with exception handling and proper parameters. We
9689      * call this the boundDirective.
9690      *
9691      * @param {string} name name of the directive to look up.
9692      * @param {string} location The directive must be found in specific format.
9693      *   String containing any of theses characters:
9694      *
9695      *   * `E`: element name
9696      *   * `A': attribute
9697      *   * `C`: class
9698      *   * `M`: comment
9699      * @returns {boolean} true if directive was added.
9700      */
9701     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
9702                           endAttrName) {
9703       if (name === ignoreDirective) return null;
9704       var match = null;
9705       if (hasDirectives.hasOwnProperty(name)) {
9706         for (var directive, directives = $injector.get(name + Suffix),
9707             i = 0, ii = directives.length; i < ii; i++) {
9708           directive = directives[i];
9709           if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
9710                directive.restrict.indexOf(location) !== -1) {
9711             if (startAttrName) {
9712               directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
9713             }
9714             if (!directive.$$bindings) {
9715               var bindings = directive.$$bindings =
9716                   parseDirectiveBindings(directive, directive.name);
9717               if (isObject(bindings.isolateScope)) {
9718                 directive.$$isolateBindings = bindings.isolateScope;
9719               }
9720             }
9721             tDirectives.push(directive);
9722             match = directive;
9723           }
9724         }
9725       }
9726       return match;
9727     }
9728
9729
9730     /**
9731      * looks up the directive and returns true if it is a multi-element directive,
9732      * and therefore requires DOM nodes between -start and -end markers to be grouped
9733      * together.
9734      *
9735      * @param {string} name name of the directive to look up.
9736      * @returns true if directive was registered as multi-element.
9737      */
9738     function directiveIsMultiElement(name) {
9739       if (hasDirectives.hasOwnProperty(name)) {
9740         for (var directive, directives = $injector.get(name + Suffix),
9741             i = 0, ii = directives.length; i < ii; i++) {
9742           directive = directives[i];
9743           if (directive.multiElement) {
9744             return true;
9745           }
9746         }
9747       }
9748       return false;
9749     }
9750
9751     /**
9752      * When the element is replaced with HTML template then the new attributes
9753      * on the template need to be merged with the existing attributes in the DOM.
9754      * The desired effect is to have both of the attributes present.
9755      *
9756      * @param {object} dst destination attributes (original DOM)
9757      * @param {object} src source attributes (from the directive template)
9758      */
9759     function mergeTemplateAttributes(dst, src) {
9760       var srcAttr = src.$attr,
9761           dstAttr = dst.$attr;
9762
9763       // reapply the old attributes to the new element
9764       forEach(dst, function(value, key) {
9765         if (key.charAt(0) !== '$') {
9766           if (src[key] && src[key] !== value) {
9767             value += (key === 'style' ? ';' : ' ') + src[key];
9768           }
9769           dst.$set(key, value, true, srcAttr[key]);
9770         }
9771       });
9772
9773       // copy the new attributes on the old attrs object
9774       forEach(src, function(value, key) {
9775         // Check if we already set this attribute in the loop above.
9776         // `dst` will never contain hasOwnProperty as DOM parser won't let it.
9777         // You will get an "InvalidCharacterError: DOM Exception 5" error if you
9778         // have an attribute like "has-own-property" or "data-has-own-property", etc.
9779         if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
9780           dst[key] = value;
9781
9782           if (key !== 'class' && key !== 'style') {
9783             dstAttr[key] = srcAttr[key];
9784           }
9785         }
9786       });
9787     }
9788
9789
9790     function compileTemplateUrl(directives, $compileNode, tAttrs,
9791         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
9792       var linkQueue = [],
9793           afterTemplateNodeLinkFn,
9794           afterTemplateChildLinkFn,
9795           beforeTemplateCompileNode = $compileNode[0],
9796           origAsyncDirective = directives.shift(),
9797           derivedSyncDirective = inherit(origAsyncDirective, {
9798             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
9799           }),
9800           templateUrl = (isFunction(origAsyncDirective.templateUrl))
9801               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
9802               : origAsyncDirective.templateUrl,
9803           templateNamespace = origAsyncDirective.templateNamespace;
9804
9805       $compileNode.empty();
9806
9807       $templateRequest(templateUrl)
9808         .then(function(content) {
9809           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
9810
9811           content = denormalizeTemplate(content);
9812
9813           if (origAsyncDirective.replace) {
9814             if (jqLiteIsTextNode(content)) {
9815               $template = [];
9816             } else {
9817               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
9818             }
9819             compileNode = $template[0];
9820
9821             if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
9822               throw $compileMinErr('tplrt',
9823                   'Template for directive \'{0}\' must have exactly one root element. {1}',
9824                   origAsyncDirective.name, templateUrl);
9825             }
9826
9827             tempTemplateAttrs = {$attr: {}};
9828             replaceWith($rootElement, $compileNode, compileNode);
9829             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
9830
9831             if (isObject(origAsyncDirective.scope)) {
9832               // the original directive that caused the template to be loaded async required
9833               // an isolate scope
9834               markDirectiveScope(templateDirectives, true);
9835             }
9836             directives = templateDirectives.concat(directives);
9837             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
9838           } else {
9839             compileNode = beforeTemplateCompileNode;
9840             $compileNode.html(content);
9841           }
9842
9843           directives.unshift(derivedSyncDirective);
9844
9845           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
9846               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
9847               previousCompileContext);
9848           forEach($rootElement, function(node, i) {
9849             if (node === compileNode) {
9850               $rootElement[i] = $compileNode[0];
9851             }
9852           });
9853           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
9854
9855           while (linkQueue.length) {
9856             var scope = linkQueue.shift(),
9857                 beforeTemplateLinkNode = linkQueue.shift(),
9858                 linkRootElement = linkQueue.shift(),
9859                 boundTranscludeFn = linkQueue.shift(),
9860                 linkNode = $compileNode[0];
9861
9862             if (scope.$$destroyed) continue;
9863
9864             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
9865               var oldClasses = beforeTemplateLinkNode.className;
9866
9867               if (!(previousCompileContext.hasElementTranscludeDirective &&
9868                   origAsyncDirective.replace)) {
9869                 // it was cloned therefore we have to clone as well.
9870                 linkNode = jqLiteClone(compileNode);
9871               }
9872               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
9873
9874               // Copy in CSS classes from original node
9875               safeAddClass(jqLite(linkNode), oldClasses);
9876             }
9877             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
9878               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
9879             } else {
9880               childBoundTranscludeFn = boundTranscludeFn;
9881             }
9882             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
9883               childBoundTranscludeFn);
9884           }
9885           linkQueue = null;
9886         });
9887
9888       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
9889         var childBoundTranscludeFn = boundTranscludeFn;
9890         if (scope.$$destroyed) return;
9891         if (linkQueue) {
9892           linkQueue.push(scope,
9893                          node,
9894                          rootElement,
9895                          childBoundTranscludeFn);
9896         } else {
9897           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
9898             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
9899           }
9900           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
9901         }
9902       };
9903     }
9904
9905
9906     /**
9907      * Sorting function for bound directives.
9908      */
9909     function byPriority(a, b) {
9910       var diff = b.priority - a.priority;
9911       if (diff !== 0) return diff;
9912       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
9913       return a.index - b.index;
9914     }
9915
9916     function assertNoDuplicate(what, previousDirective, directive, element) {
9917
9918       function wrapModuleNameIfDefined(moduleName) {
9919         return moduleName ?
9920           (' (module: ' + moduleName + ')') :
9921           '';
9922       }
9923
9924       if (previousDirective) {
9925         throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
9926             previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
9927             directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
9928       }
9929     }
9930
9931
9932     function addTextInterpolateDirective(directives, text) {
9933       var interpolateFn = $interpolate(text, true);
9934       if (interpolateFn) {
9935         directives.push({
9936           priority: 0,
9937           compile: function textInterpolateCompileFn(templateNode) {
9938             var templateNodeParent = templateNode.parent(),
9939                 hasCompileParent = !!templateNodeParent.length;
9940
9941             // When transcluding a template that has bindings in the root
9942             // we don't have a parent and thus need to add the class during linking fn.
9943             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
9944
9945             return function textInterpolateLinkFn(scope, node) {
9946               var parent = node.parent();
9947               if (!hasCompileParent) compile.$$addBindingClass(parent);
9948               compile.$$addBindingInfo(parent, interpolateFn.expressions);
9949               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
9950                 node[0].nodeValue = value;
9951               });
9952             };
9953           }
9954         });
9955       }
9956     }
9957
9958
9959     function wrapTemplate(type, template) {
9960       type = lowercase(type || 'html');
9961       switch (type) {
9962       case 'svg':
9963       case 'math':
9964         var wrapper = window.document.createElement('div');
9965         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
9966         return wrapper.childNodes[0].childNodes;
9967       default:
9968         return template;
9969       }
9970     }
9971
9972
9973     function getTrustedContext(node, attrNormalizedName) {
9974       if (attrNormalizedName === 'srcdoc') {
9975         return $sce.HTML;
9976       }
9977       var tag = nodeName_(node);
9978       // All tags with src attributes require a RESOURCE_URL value, except for
9979       // img and various html5 media tags.
9980       if (attrNormalizedName === 'src' || attrNormalizedName === 'ngSrc') {
9981         if (['img', 'video', 'audio', 'source', 'track'].indexOf(tag) === -1) {
9982           return $sce.RESOURCE_URL;
9983         }
9984       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
9985       } else if (attrNormalizedName === 'xlinkHref' ||
9986           (tag === 'form' && attrNormalizedName === 'action')
9987       ) {
9988         return $sce.RESOURCE_URL;
9989       }
9990     }
9991
9992
9993     function addAttrInterpolateDirective(node, directives, value, name, isNgAttr) {
9994       var trustedContext = getTrustedContext(node, name);
9995       var mustHaveExpression = !isNgAttr;
9996       var allOrNothing = ALL_OR_NOTHING_ATTRS[name] || isNgAttr;
9997
9998       var interpolateFn = $interpolate(value, mustHaveExpression, trustedContext, allOrNothing);
9999
10000       // no interpolation found -> ignore
10001       if (!interpolateFn) return;
10002
10003       if (name === 'multiple' && nodeName_(node) === 'select') {
10004         throw $compileMinErr('selmulti',
10005             'Binding to the \'multiple\' attribute is not supported. Element: {0}',
10006             startingTag(node));
10007       }
10008
10009       directives.push({
10010         priority: 100,
10011         compile: function() {
10012             return {
10013               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
10014                 var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
10015
10016                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
10017                   throw $compileMinErr('nodomevents',
10018                       'Interpolations for HTML DOM event attributes are disallowed.  Please use the ' +
10019                           'ng- versions (such as ng-click instead of onclick) instead.');
10020                 }
10021
10022                 // If the attribute has changed since last $interpolate()ed
10023                 var newValue = attr[name];
10024                 if (newValue !== value) {
10025                   // we need to interpolate again since the attribute value has been updated
10026                   // (e.g. by another directive's compile function)
10027                   // ensure unset/empty values make interpolateFn falsy
10028                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
10029                   value = newValue;
10030                 }
10031
10032                 // if attribute was updated so that there is no interpolation going on we don't want to
10033                 // register any observers
10034                 if (!interpolateFn) return;
10035
10036                 // initialize attr object so that it's ready in case we need the value for isolate
10037                 // scope initialization, otherwise the value would not be available from isolate
10038                 // directive's linking fn during linking phase
10039                 attr[name] = interpolateFn(scope);
10040
10041                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
10042                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
10043                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
10044                     //special case for class attribute addition + removal
10045                     //so that class changes can tap into the animation
10046                     //hooks provided by the $animate service. Be sure to
10047                     //skip animations when the first digest occurs (when
10048                     //both the new and the old values are the same) since
10049                     //the CSS classes are the non-interpolated values
10050                     if (name === 'class' && newValue !== oldValue) {
10051                       attr.$updateClass(newValue, oldValue);
10052                     } else {
10053                       attr.$set(name, newValue);
10054                     }
10055                   });
10056               }
10057             };
10058           }
10059       });
10060     }
10061
10062
10063     /**
10064      * This is a special jqLite.replaceWith, which can replace items which
10065      * have no parents, provided that the containing jqLite collection is provided.
10066      *
10067      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
10068      *                               in the root of the tree.
10069      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
10070      *                                  the shell, but replace its DOM node reference.
10071      * @param {Node} newNode The new DOM node.
10072      */
10073     function replaceWith($rootElement, elementsToRemove, newNode) {
10074       var firstElementToRemove = elementsToRemove[0],
10075           removeCount = elementsToRemove.length,
10076           parent = firstElementToRemove.parentNode,
10077           i, ii;
10078
10079       if ($rootElement) {
10080         for (i = 0, ii = $rootElement.length; i < ii; i++) {
10081           if ($rootElement[i] === firstElementToRemove) {
10082             $rootElement[i++] = newNode;
10083             for (var j = i, j2 = j + removeCount - 1,
10084                      jj = $rootElement.length;
10085                  j < jj; j++, j2++) {
10086               if (j2 < jj) {
10087                 $rootElement[j] = $rootElement[j2];
10088               } else {
10089                 delete $rootElement[j];
10090               }
10091             }
10092             $rootElement.length -= removeCount - 1;
10093
10094             // If the replaced element is also the jQuery .context then replace it
10095             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
10096             // http://api.jquery.com/context/
10097             if ($rootElement.context === firstElementToRemove) {
10098               $rootElement.context = newNode;
10099             }
10100             break;
10101           }
10102         }
10103       }
10104
10105       if (parent) {
10106         parent.replaceChild(newNode, firstElementToRemove);
10107       }
10108
10109       // Append all the `elementsToRemove` to a fragment. This will...
10110       // - remove them from the DOM
10111       // - allow them to still be traversed with .nextSibling
10112       // - allow a single fragment.qSA to fetch all elements being removed
10113       var fragment = window.document.createDocumentFragment();
10114       for (i = 0; i < removeCount; i++) {
10115         fragment.appendChild(elementsToRemove[i]);
10116       }
10117
10118       if (jqLite.hasData(firstElementToRemove)) {
10119         // Copy over user data (that includes Angular's $scope etc.). Don't copy private
10120         // data here because there's no public interface in jQuery to do that and copying over
10121         // event listeners (which is the main use of private data) wouldn't work anyway.
10122         jqLite.data(newNode, jqLite.data(firstElementToRemove));
10123
10124         // Remove $destroy event listeners from `firstElementToRemove`
10125         jqLite(firstElementToRemove).off('$destroy');
10126       }
10127
10128       // Cleanup any data/listeners on the elements and children.
10129       // This includes invoking the $destroy event on any elements with listeners.
10130       jqLite.cleanData(fragment.querySelectorAll('*'));
10131
10132       // Update the jqLite collection to only contain the `newNode`
10133       for (i = 1; i < removeCount; i++) {
10134         delete elementsToRemove[i];
10135       }
10136       elementsToRemove[0] = newNode;
10137       elementsToRemove.length = 1;
10138     }
10139
10140
10141     function cloneAndAnnotateFn(fn, annotation) {
10142       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
10143     }
10144
10145
10146     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
10147       try {
10148         linkFn(scope, $element, attrs, controllers, transcludeFn);
10149       } catch (e) {
10150         $exceptionHandler(e, startingTag($element));
10151       }
10152     }
10153
10154
10155     // Set up $watches for isolate scope and controller bindings.
10156     function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
10157       var removeWatchCollection = [];
10158       var initialChanges = {};
10159       var changes;
10160       forEach(bindings, function initializeBinding(definition, scopeName) {
10161         var attrName = definition.attrName,
10162         optional = definition.optional,
10163         mode = definition.mode, // @, =, <, or &
10164         lastValue,
10165         parentGet, parentSet, compare, removeWatch;
10166
10167         switch (mode) {
10168
10169           case '@':
10170             if (!optional && !hasOwnProperty.call(attrs, attrName)) {
10171               destination[scopeName] = attrs[attrName] = undefined;
10172             }
10173             removeWatch = attrs.$observe(attrName, function(value) {
10174               if (isString(value) || isBoolean(value)) {
10175                 var oldValue = destination[scopeName];
10176                 recordChanges(scopeName, value, oldValue);
10177                 destination[scopeName] = value;
10178               }
10179             });
10180             attrs.$$observers[attrName].$$scope = scope;
10181             lastValue = attrs[attrName];
10182             if (isString(lastValue)) {
10183               // If the attribute has been provided then we trigger an interpolation to ensure
10184               // the value is there for use in the link fn
10185               destination[scopeName] = $interpolate(lastValue)(scope);
10186             } else if (isBoolean(lastValue)) {
10187               // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
10188               // the value to boolean rather than a string, so we special case this situation
10189               destination[scopeName] = lastValue;
10190             }
10191             initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
10192             removeWatchCollection.push(removeWatch);
10193             break;
10194
10195           case '=':
10196             if (!hasOwnProperty.call(attrs, attrName)) {
10197               if (optional) break;
10198               attrs[attrName] = undefined;
10199             }
10200             if (optional && !attrs[attrName]) break;
10201
10202             parentGet = $parse(attrs[attrName]);
10203             if (parentGet.literal) {
10204               compare = equals;
10205             } else {
10206               // eslint-disable-next-line no-self-compare
10207               compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };
10208             }
10209             parentSet = parentGet.assign || function() {
10210               // reset the change, or we will throw this exception on every $digest
10211               lastValue = destination[scopeName] = parentGet(scope);
10212               throw $compileMinErr('nonassign',
10213                   'Expression \'{0}\' in attribute \'{1}\' used with directive \'{2}\' is non-assignable!',
10214                   attrs[attrName], attrName, directive.name);
10215             };
10216             lastValue = destination[scopeName] = parentGet(scope);
10217             var parentValueWatch = function parentValueWatch(parentValue) {
10218               if (!compare(parentValue, destination[scopeName])) {
10219                 // we are out of sync and need to copy
10220                 if (!compare(parentValue, lastValue)) {
10221                   // parent changed and it has precedence
10222                   destination[scopeName] = parentValue;
10223                 } else {
10224                   // if the parent can be assigned then do so
10225                   parentSet(scope, parentValue = destination[scopeName]);
10226                 }
10227               }
10228               lastValue = parentValue;
10229               return lastValue;
10230             };
10231             parentValueWatch.$stateful = true;
10232             if (definition.collection) {
10233               removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
10234             } else {
10235               removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
10236             }
10237             removeWatchCollection.push(removeWatch);
10238             break;
10239
10240           case '<':
10241             if (!hasOwnProperty.call(attrs, attrName)) {
10242               if (optional) break;
10243               attrs[attrName] = undefined;
10244             }
10245             if (optional && !attrs[attrName]) break;
10246
10247             parentGet = $parse(attrs[attrName]);
10248             var deepWatch = parentGet.literal;
10249
10250             var initialValue = destination[scopeName] = parentGet(scope);
10251             initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
10252
10253             removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
10254               if (oldValue === newValue) {
10255                 if (oldValue === initialValue || (deepWatch && equals(oldValue, initialValue))) {
10256                   return;
10257                 }
10258                 oldValue = initialValue;
10259               }
10260               recordChanges(scopeName, newValue, oldValue);
10261               destination[scopeName] = newValue;
10262             }, deepWatch);
10263
10264             removeWatchCollection.push(removeWatch);
10265             break;
10266
10267           case '&':
10268             // Don't assign Object.prototype method to scope
10269             parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
10270
10271             // Don't assign noop to destination if expression is not valid
10272             if (parentGet === noop && optional) break;
10273
10274             destination[scopeName] = function(locals) {
10275               return parentGet(scope, locals);
10276             };
10277             break;
10278         }
10279       });
10280
10281       function recordChanges(key, currentValue, previousValue) {
10282         if (isFunction(destination.$onChanges) && currentValue !== previousValue &&
10283             // eslint-disable-next-line no-self-compare
10284             (currentValue === currentValue || previousValue === previousValue)) {
10285           // If we have not already scheduled the top level onChangesQueue handler then do so now
10286           if (!onChangesQueue) {
10287             scope.$$postDigest(flushOnChangesQueue);
10288             onChangesQueue = [];
10289           }
10290           // If we have not already queued a trigger of onChanges for this controller then do so now
10291           if (!changes) {
10292             changes = {};
10293             onChangesQueue.push(triggerOnChangesHook);
10294           }
10295           // If the has been a change on this property already then we need to reuse the previous value
10296           if (changes[key]) {
10297             previousValue = changes[key].previousValue;
10298           }
10299           // Store this change
10300           changes[key] = new SimpleChange(previousValue, currentValue);
10301         }
10302       }
10303
10304       function triggerOnChangesHook() {
10305         destination.$onChanges(changes);
10306         // Now clear the changes so that we schedule onChanges when more changes arrive
10307         changes = undefined;
10308       }
10309
10310       return {
10311         initialChanges: initialChanges,
10312         removeWatches: removeWatchCollection.length && function removeWatches() {
10313           for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
10314             removeWatchCollection[i]();
10315           }
10316         }
10317       };
10318     }
10319   }];
10320 }
10321
10322 function SimpleChange(previous, current) {
10323   this.previousValue = previous;
10324   this.currentValue = current;
10325 }
10326 SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
10327
10328
10329 var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
10330 /**
10331  * Converts all accepted directives format into proper directive name.
10332  * @param name Name to normalize
10333  */
10334 function directiveNormalize(name) {
10335   return camelCase(name.replace(PREFIX_REGEXP, ''));
10336 }
10337
10338 /**
10339  * @ngdoc type
10340  * @name $compile.directive.Attributes
10341  *
10342  * @description
10343  * A shared object between directive compile / linking functions which contains normalized DOM
10344  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
10345  * needed since all of these are treated as equivalent in Angular:
10346  *
10347  * ```
10348  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
10349  * ```
10350  */
10351
10352 /**
10353  * @ngdoc property
10354  * @name $compile.directive.Attributes#$attr
10355  *
10356  * @description
10357  * A map of DOM element attribute names to the normalized name. This is
10358  * needed to do reverse lookup from normalized name back to actual name.
10359  */
10360
10361
10362 /**
10363  * @ngdoc method
10364  * @name $compile.directive.Attributes#$set
10365  * @kind function
10366  *
10367  * @description
10368  * Set DOM element attribute value.
10369  *
10370  *
10371  * @param {string} name Normalized element attribute name of the property to modify. The name is
10372  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
10373  *          property to the original name.
10374  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
10375  */
10376
10377
10378
10379 /**
10380  * Closure compiler type information
10381  */
10382
10383 function nodesetLinkingFn(
10384   /* angular.Scope */ scope,
10385   /* NodeList */ nodeList,
10386   /* Element */ rootElement,
10387   /* function(Function) */ boundTranscludeFn
10388 ) {}
10389
10390 function directiveLinkingFn(
10391   /* nodesetLinkingFn */ nodesetLinkingFn,
10392   /* angular.Scope */ scope,
10393   /* Node */ node,
10394   /* Element */ rootElement,
10395   /* function(Function) */ boundTranscludeFn
10396 ) {}
10397
10398 function tokenDifference(str1, str2) {
10399   var values = '',
10400       tokens1 = str1.split(/\s+/),
10401       tokens2 = str2.split(/\s+/);
10402
10403   outer:
10404   for (var i = 0; i < tokens1.length; i++) {
10405     var token = tokens1[i];
10406     for (var j = 0; j < tokens2.length; j++) {
10407       if (token === tokens2[j]) continue outer;
10408     }
10409     values += (values.length > 0 ? ' ' : '') + token;
10410   }
10411   return values;
10412 }
10413
10414 function removeComments(jqNodes) {
10415   jqNodes = jqLite(jqNodes);
10416   var i = jqNodes.length;
10417
10418   if (i <= 1) {
10419     return jqNodes;
10420   }
10421
10422   while (i--) {
10423     var node = jqNodes[i];
10424     if (node.nodeType === NODE_TYPE_COMMENT ||
10425        (node.nodeType === NODE_TYPE_TEXT && node.nodeValue.trim() === '')) {
10426          splice.call(jqNodes, i, 1);
10427     }
10428   }
10429   return jqNodes;
10430 }
10431
10432 var $controllerMinErr = minErr('$controller');
10433
10434
10435 var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
10436 function identifierForController(controller, ident) {
10437   if (ident && isString(ident)) return ident;
10438   if (isString(controller)) {
10439     var match = CNTRL_REG.exec(controller);
10440     if (match) return match[3];
10441   }
10442 }
10443
10444
10445 /**
10446  * @ngdoc provider
10447  * @name $controllerProvider
10448  * @this
10449  *
10450  * @description
10451  * The {@link ng.$controller $controller service} is used by Angular to create new
10452  * controllers.
10453  *
10454  * This provider allows controller registration via the
10455  * {@link ng.$controllerProvider#register register} method.
10456  */
10457 function $ControllerProvider() {
10458   var controllers = {},
10459       globals = false;
10460
10461   /**
10462    * @ngdoc method
10463    * @name $controllerProvider#has
10464    * @param {string} name Controller name to check.
10465    */
10466   this.has = function(name) {
10467     return controllers.hasOwnProperty(name);
10468   };
10469
10470   /**
10471    * @ngdoc method
10472    * @name $controllerProvider#register
10473    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
10474    *    the names and the values are the constructors.
10475    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
10476    *    annotations in the array notation).
10477    */
10478   this.register = function(name, constructor) {
10479     assertNotHasOwnProperty(name, 'controller');
10480     if (isObject(name)) {
10481       extend(controllers, name);
10482     } else {
10483       controllers[name] = constructor;
10484     }
10485   };
10486
10487   /**
10488    * @ngdoc method
10489    * @name $controllerProvider#allowGlobals
10490    *
10491    * @deprecated
10492    * sinceVersion="v1.3.0"
10493    * removeVersion="v1.7.0"
10494    * This method of finding controllers has been deprecated.
10495    *
10496    * @description If called, allows `$controller` to find controller constructors on `window`   *
10497    */
10498   this.allowGlobals = function() {
10499     globals = true;
10500   };
10501
10502
10503   this.$get = ['$injector', '$window', function($injector, $window) {
10504
10505     /**
10506      * @ngdoc service
10507      * @name $controller
10508      * @requires $injector
10509      *
10510      * @param {Function|string} constructor If called with a function then it's considered to be the
10511      *    controller constructor function. Otherwise it's considered to be a string which is used
10512      *    to retrieve the controller constructor using the following steps:
10513      *
10514      *    * check if a controller with given name is registered via `$controllerProvider`
10515      *    * check if evaluating the string on the current scope returns a constructor
10516      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
10517      *      `window` object (not recommended)
10518      *
10519      *    The string can use the `controller as property` syntax, where the controller instance is published
10520      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
10521      *    to work correctly.
10522      *
10523      * @param {Object} locals Injection locals for Controller.
10524      * @return {Object} Instance of given controller.
10525      *
10526      * @description
10527      * `$controller` service is responsible for instantiating controllers.
10528      *
10529      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
10530      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
10531      */
10532     return function $controller(expression, locals, later, ident) {
10533       // PRIVATE API:
10534       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
10535       //                     If true, $controller will allocate the object with the correct
10536       //                     prototype chain, but will not invoke the controller until a returned
10537       //                     callback is invoked.
10538       //   param `ident` --- An optional label which overrides the label parsed from the controller
10539       //                     expression, if any.
10540       var instance, match, constructor, identifier;
10541       later = later === true;
10542       if (ident && isString(ident)) {
10543         identifier = ident;
10544       }
10545
10546       if (isString(expression)) {
10547         match = expression.match(CNTRL_REG);
10548         if (!match) {
10549           throw $controllerMinErr('ctrlfmt',
10550             'Badly formed controller string \'{0}\'. ' +
10551             'Must match `__name__ as __id__` or `__name__`.', expression);
10552         }
10553         constructor = match[1];
10554         identifier = identifier || match[3];
10555         expression = controllers.hasOwnProperty(constructor)
10556             ? controllers[constructor]
10557             : getter(locals.$scope, constructor, true) ||
10558                 (globals ? getter($window, constructor, true) : undefined);
10559
10560         if (!expression) {
10561           throw $controllerMinErr('ctrlreg',
10562             'The controller with the name \'{0}\' is not registered.', constructor);
10563         }
10564
10565         assertArgFn(expression, constructor, true);
10566       }
10567
10568       if (later) {
10569         // Instantiate controller later:
10570         // This machinery is used to create an instance of the object before calling the
10571         // controller's constructor itself.
10572         //
10573         // This allows properties to be added to the controller before the constructor is
10574         // invoked. Primarily, this is used for isolate scope bindings in $compile.
10575         //
10576         // This feature is not intended for use by applications, and is thus not documented
10577         // publicly.
10578         // Object creation: http://jsperf.com/create-constructor/2
10579         var controllerPrototype = (isArray(expression) ?
10580           expression[expression.length - 1] : expression).prototype;
10581         instance = Object.create(controllerPrototype || null);
10582
10583         if (identifier) {
10584           addIdentifier(locals, identifier, instance, constructor || expression.name);
10585         }
10586
10587         return extend(function $controllerInit() {
10588           var result = $injector.invoke(expression, instance, locals, constructor);
10589           if (result !== instance && (isObject(result) || isFunction(result))) {
10590             instance = result;
10591             if (identifier) {
10592               // If result changed, re-assign controllerAs value to scope.
10593               addIdentifier(locals, identifier, instance, constructor || expression.name);
10594             }
10595           }
10596           return instance;
10597         }, {
10598           instance: instance,
10599           identifier: identifier
10600         });
10601       }
10602
10603       instance = $injector.instantiate(expression, locals, constructor);
10604
10605       if (identifier) {
10606         addIdentifier(locals, identifier, instance, constructor || expression.name);
10607       }
10608
10609       return instance;
10610     };
10611
10612     function addIdentifier(locals, identifier, instance, name) {
10613       if (!(locals && isObject(locals.$scope))) {
10614         throw minErr('$controller')('noscp',
10615           'Cannot export controller \'{0}\' as \'{1}\'! No $scope object provided via `locals`.',
10616           name, identifier);
10617       }
10618
10619       locals.$scope[identifier] = instance;
10620     }
10621   }];
10622 }
10623
10624 /**
10625  * @ngdoc service
10626  * @name $document
10627  * @requires $window
10628  * @this
10629  *
10630  * @description
10631  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
10632  *
10633  * @example
10634    <example module="documentExample" name="document">
10635      <file name="index.html">
10636        <div ng-controller="ExampleController">
10637          <p>$document title: <b ng-bind="title"></b></p>
10638          <p>window.document title: <b ng-bind="windowTitle"></b></p>
10639        </div>
10640      </file>
10641      <file name="script.js">
10642        angular.module('documentExample', [])
10643          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
10644            $scope.title = $document[0].title;
10645            $scope.windowTitle = angular.element(window.document)[0].title;
10646          }]);
10647      </file>
10648    </example>
10649  */
10650 function $DocumentProvider() {
10651   this.$get = ['$window', function(window) {
10652     return jqLite(window.document);
10653   }];
10654 }
10655
10656 /**
10657  * @ngdoc service
10658  * @name $exceptionHandler
10659  * @requires ng.$log
10660  * @this
10661  *
10662  * @description
10663  * Any uncaught exception in angular expressions is delegated to this service.
10664  * The default implementation simply delegates to `$log.error` which logs it into
10665  * the browser console.
10666  *
10667  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
10668  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
10669  *
10670  * ## Example:
10671  *
10672  * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught
10673  * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead
10674  * of `$log.error()`.
10675  *
10676  * ```js
10677  *   angular.
10678  *     module('exceptionOverwrite', []).
10679  *     factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
10680  *       return function myExceptionHandler(exception, cause) {
10681  *         logErrorsToBackend(exception, cause);
10682  *         $log.warn(exception, cause);
10683  *       };
10684  *     }]);
10685  * ```
10686  *
10687  * <hr />
10688  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
10689  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
10690  * (unless executed during a digest).
10691  *
10692  * If you wish, you can manually delegate exceptions, e.g.
10693  * `try { ... } catch(e) { $exceptionHandler(e); }`
10694  *
10695  * @param {Error} exception Exception associated with the error.
10696  * @param {string=} cause Optional information about the context in which
10697  *       the error was thrown.
10698  *
10699  */
10700 function $ExceptionHandlerProvider() {
10701   this.$get = ['$log', function($log) {
10702     return function(exception, cause) {
10703       $log.error.apply($log, arguments);
10704     };
10705   }];
10706 }
10707
10708 var $$ForceReflowProvider = /** @this */ function() {
10709   this.$get = ['$document', function($document) {
10710     return function(domNode) {
10711       //the line below will force the browser to perform a repaint so
10712       //that all the animated elements within the animation frame will
10713       //be properly updated and drawn on screen. This is required to
10714       //ensure that the preparation animation is properly flushed so that
10715       //the active state picks up from there. DO NOT REMOVE THIS LINE.
10716       //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
10717       //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
10718       //WILL TAKE YEARS AWAY FROM YOUR LIFE.
10719       if (domNode) {
10720         if (!domNode.nodeType && domNode instanceof jqLite) {
10721           domNode = domNode[0];
10722         }
10723       } else {
10724         domNode = $document[0].body;
10725       }
10726       return domNode.offsetWidth + 1;
10727     };
10728   }];
10729 };
10730
10731 var APPLICATION_JSON = 'application/json';
10732 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
10733 var JSON_START = /^\[|^\{(?!\{)/;
10734 var JSON_ENDS = {
10735   '[': /]$/,
10736   '{': /}$/
10737 };
10738 var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/;
10739 var $httpMinErr = minErr('$http');
10740 var $httpMinErrLegacyFn = function(method) {
10741   return function() {
10742     throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
10743   };
10744 };
10745
10746 function serializeValue(v) {
10747   if (isObject(v)) {
10748     return isDate(v) ? v.toISOString() : toJson(v);
10749   }
10750   return v;
10751 }
10752
10753
10754 /** @this */
10755 function $HttpParamSerializerProvider() {
10756   /**
10757    * @ngdoc service
10758    * @name $httpParamSerializer
10759    * @description
10760    *
10761    * Default {@link $http `$http`} params serializer that converts objects to strings
10762    * according to the following rules:
10763    *
10764    * * `{'foo': 'bar'}` results in `foo=bar`
10765    * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
10766    * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
10767    * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
10768    *
10769    * Note that serializer will sort the request parameters alphabetically.
10770    * */
10771
10772   this.$get = function() {
10773     return function ngParamSerializer(params) {
10774       if (!params) return '';
10775       var parts = [];
10776       forEachSorted(params, function(value, key) {
10777         if (value === null || isUndefined(value)) return;
10778         if (isArray(value)) {
10779           forEach(value, function(v) {
10780             parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
10781           });
10782         } else {
10783           parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
10784         }
10785       });
10786
10787       return parts.join('&');
10788     };
10789   };
10790 }
10791
10792 /** @this */
10793 function $HttpParamSerializerJQLikeProvider() {
10794   /**
10795    * @ngdoc service
10796    * @name $httpParamSerializerJQLike
10797    *
10798    * @description
10799    *
10800    * Alternative {@link $http `$http`} params serializer that follows
10801    * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
10802    * The serializer will also sort the params alphabetically.
10803    *
10804    * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
10805    *
10806    * ```js
10807    * $http({
10808    *   url: myUrl,
10809    *   method: 'GET',
10810    *   params: myParams,
10811    *   paramSerializer: '$httpParamSerializerJQLike'
10812    * });
10813    * ```
10814    *
10815    * It is also possible to set it as the default `paramSerializer` in the
10816    * {@link $httpProvider#defaults `$httpProvider`}.
10817    *
10818    * Additionally, you can inject the serializer and use it explicitly, for example to serialize
10819    * form data for submission:
10820    *
10821    * ```js
10822    * .controller(function($http, $httpParamSerializerJQLike) {
10823    *   //...
10824    *
10825    *   $http({
10826    *     url: myUrl,
10827    *     method: 'POST',
10828    *     data: $httpParamSerializerJQLike(myData),
10829    *     headers: {
10830    *       'Content-Type': 'application/x-www-form-urlencoded'
10831    *     }
10832    *   });
10833    *
10834    * });
10835    * ```
10836    *
10837    * */
10838   this.$get = function() {
10839     return function jQueryLikeParamSerializer(params) {
10840       if (!params) return '';
10841       var parts = [];
10842       serialize(params, '', true);
10843       return parts.join('&');
10844
10845       function serialize(toSerialize, prefix, topLevel) {
10846         if (toSerialize === null || isUndefined(toSerialize)) return;
10847         if (isArray(toSerialize)) {
10848           forEach(toSerialize, function(value, index) {
10849             serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
10850           });
10851         } else if (isObject(toSerialize) && !isDate(toSerialize)) {
10852           forEachSorted(toSerialize, function(value, key) {
10853             serialize(value, prefix +
10854                 (topLevel ? '' : '[') +
10855                 key +
10856                 (topLevel ? '' : ']'));
10857           });
10858         } else {
10859           parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
10860         }
10861       }
10862     };
10863   };
10864 }
10865
10866 function defaultHttpResponseTransform(data, headers) {
10867   if (isString(data)) {
10868     // Strip json vulnerability protection prefix and trim whitespace
10869     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
10870
10871     if (tempData) {
10872       var contentType = headers('Content-Type');
10873       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
10874         data = fromJson(tempData);
10875       }
10876     }
10877   }
10878
10879   return data;
10880 }
10881
10882 function isJsonLike(str) {
10883     var jsonStart = str.match(JSON_START);
10884     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
10885 }
10886
10887 /**
10888  * Parse headers into key value object
10889  *
10890  * @param {string} headers Raw headers as a string
10891  * @returns {Object} Parsed headers as key value object
10892  */
10893 function parseHeaders(headers) {
10894   var parsed = createMap(), i;
10895
10896   function fillInParsed(key, val) {
10897     if (key) {
10898       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
10899     }
10900   }
10901
10902   if (isString(headers)) {
10903     forEach(headers.split('\n'), function(line) {
10904       i = line.indexOf(':');
10905       fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
10906     });
10907   } else if (isObject(headers)) {
10908     forEach(headers, function(headerVal, headerKey) {
10909       fillInParsed(lowercase(headerKey), trim(headerVal));
10910     });
10911   }
10912
10913   return parsed;
10914 }
10915
10916
10917 /**
10918  * Returns a function that provides access to parsed headers.
10919  *
10920  * Headers are lazy parsed when first requested.
10921  * @see parseHeaders
10922  *
10923  * @param {(string|Object)} headers Headers to provide access to.
10924  * @returns {function(string=)} Returns a getter function which if called with:
10925  *
10926  *   - if called with an argument returns a single header value or null
10927  *   - if called with no arguments returns an object containing all headers.
10928  */
10929 function headersGetter(headers) {
10930   var headersObj;
10931
10932   return function(name) {
10933     if (!headersObj) headersObj =  parseHeaders(headers);
10934
10935     if (name) {
10936       var value = headersObj[lowercase(name)];
10937       if (value === undefined) {
10938         value = null;
10939       }
10940       return value;
10941     }
10942
10943     return headersObj;
10944   };
10945 }
10946
10947
10948 /**
10949  * Chain all given functions
10950  *
10951  * This function is used for both request and response transforming
10952  *
10953  * @param {*} data Data to transform.
10954  * @param {function(string=)} headers HTTP headers getter fn.
10955  * @param {number} status HTTP status code of the response.
10956  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
10957  * @returns {*} Transformed data.
10958  */
10959 function transformData(data, headers, status, fns) {
10960   if (isFunction(fns)) {
10961     return fns(data, headers, status);
10962   }
10963
10964   forEach(fns, function(fn) {
10965     data = fn(data, headers, status);
10966   });
10967
10968   return data;
10969 }
10970
10971
10972 function isSuccess(status) {
10973   return 200 <= status && status < 300;
10974 }
10975
10976
10977 /**
10978  * @ngdoc provider
10979  * @name $httpProvider
10980  * @this
10981  *
10982  * @description
10983  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
10984  * */
10985 function $HttpProvider() {
10986   /**
10987    * @ngdoc property
10988    * @name $httpProvider#defaults
10989    * @description
10990    *
10991    * Object containing default values for all {@link ng.$http $http} requests.
10992    *
10993    * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
10994    * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
10995    * by default. See {@link $http#caching $http Caching} for more information.
10996    *
10997    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
10998    * Defaults value is `'XSRF-TOKEN'`.
10999    *
11000    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
11001    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
11002    *
11003    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
11004    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
11005    * setting default headers.
11006    *     - **`defaults.headers.common`**
11007    *     - **`defaults.headers.post`**
11008    *     - **`defaults.headers.put`**
11009    *     - **`defaults.headers.patch`**
11010    *
11011    *
11012    * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
11013    *  used to the prepare string representation of request parameters (specified as an object).
11014    *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
11015    *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
11016    *
11017    **/
11018   var defaults = this.defaults = {
11019     // transform incoming response data
11020     transformResponse: [defaultHttpResponseTransform],
11021
11022     // transform outgoing request data
11023     transformRequest: [function(d) {
11024       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
11025     }],
11026
11027     // default headers
11028     headers: {
11029       common: {
11030         'Accept': 'application/json, text/plain, */*'
11031       },
11032       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
11033       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
11034       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
11035     },
11036
11037     xsrfCookieName: 'XSRF-TOKEN',
11038     xsrfHeaderName: 'X-XSRF-TOKEN',
11039
11040     paramSerializer: '$httpParamSerializer'
11041   };
11042
11043   var useApplyAsync = false;
11044   /**
11045    * @ngdoc method
11046    * @name $httpProvider#useApplyAsync
11047    * @description
11048    *
11049    * Configure $http service to combine processing of multiple http responses received at around
11050    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
11051    * significant performance improvement for bigger applications that make many HTTP requests
11052    * concurrently (common during application bootstrap).
11053    *
11054    * Defaults to false. If no value is specified, returns the current configured value.
11055    *
11056    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
11057    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
11058    *    to load and share the same digest cycle.
11059    *
11060    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
11061    *    otherwise, returns the current configured value.
11062    **/
11063   this.useApplyAsync = function(value) {
11064     if (isDefined(value)) {
11065       useApplyAsync = !!value;
11066       return this;
11067     }
11068     return useApplyAsync;
11069   };
11070
11071   var useLegacyPromise = true;
11072   /**
11073    * @ngdoc method
11074    * @name $httpProvider#useLegacyPromiseExtensions
11075    * @description
11076    *
11077    * @deprecated
11078    * sinceVersion="v1.4.4"
11079    * removeVersion="v1.6.0"
11080    * This method will be removed in v1.6.0 along with the legacy promise methods.
11081    *
11082    * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
11083    * This should be used to make sure that applications work without these methods.
11084    *
11085    * Defaults to true. If no value is specified, returns the current configured value.
11086    *
11087    * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
11088    *
11089    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
11090    *    otherwise, returns the current configured value.
11091    **/
11092   this.useLegacyPromiseExtensions = function(value) {
11093     if (isDefined(value)) {
11094       useLegacyPromise = !!value;
11095       return this;
11096     }
11097     return useLegacyPromise;
11098   };
11099
11100   /**
11101    * @ngdoc property
11102    * @name $httpProvider#interceptors
11103    * @description
11104    *
11105    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
11106    * pre-processing of request or postprocessing of responses.
11107    *
11108    * These service factories are ordered by request, i.e. they are applied in the same order as the
11109    * array, on request, but reverse order, on response.
11110    *
11111    * {@link ng.$http#interceptors Interceptors detailed info}
11112    **/
11113   var interceptorFactories = this.interceptors = [];
11114
11115   this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
11116       function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
11117
11118     var defaultCache = $cacheFactory('$http');
11119
11120     /**
11121      * Make sure that default param serializer is exposed as a function
11122      */
11123     defaults.paramSerializer = isString(defaults.paramSerializer) ?
11124       $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
11125
11126     /**
11127      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
11128      * The reversal is needed so that we can build up the interception chain around the
11129      * server request.
11130      */
11131     var reversedInterceptors = [];
11132
11133     forEach(interceptorFactories, function(interceptorFactory) {
11134       reversedInterceptors.unshift(isString(interceptorFactory)
11135           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
11136     });
11137
11138     /**
11139      * @ngdoc service
11140      * @kind function
11141      * @name $http
11142      * @requires ng.$httpBackend
11143      * @requires $cacheFactory
11144      * @requires $rootScope
11145      * @requires $q
11146      * @requires $injector
11147      *
11148      * @description
11149      * The `$http` service is a core Angular service that facilitates communication with the remote
11150      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
11151      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
11152      *
11153      * For unit testing applications that use `$http` service, see
11154      * {@link ngMock.$httpBackend $httpBackend mock}.
11155      *
11156      * For a higher level of abstraction, please check out the {@link ngResource.$resource
11157      * $resource} service.
11158      *
11159      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
11160      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
11161      * it is important to familiarize yourself with these APIs and the guarantees they provide.
11162      *
11163      *
11164      * ## General usage
11165      * The `$http` service is a function which takes a single argument â€” a {@link $http#usage configuration object} â€”
11166      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
11167      *
11168      * ```js
11169      *   // Simple GET request example:
11170      *   $http({
11171      *     method: 'GET',
11172      *     url: '/someUrl'
11173      *   }).then(function successCallback(response) {
11174      *       // this callback will be called asynchronously
11175      *       // when the response is available
11176      *     }, function errorCallback(response) {
11177      *       // called asynchronously if an error occurs
11178      *       // or server returns response with an error status.
11179      *     });
11180      * ```
11181      *
11182      * The response object has these properties:
11183      *
11184      *   - **data** â€“ `{string|Object}` â€“ The response body transformed with the transform
11185      *     functions.
11186      *   - **status** â€“ `{number}` â€“ HTTP status code of the response.
11187      *   - **headers** â€“ `{function([headerName])}` â€“ Header getter function.
11188      *   - **config** â€“ `{Object}` â€“ The configuration object that was used to generate the request.
11189      *   - **statusText** â€“ `{string}` â€“ HTTP status text of the response.
11190      *
11191      * A response status code between 200 and 299 is considered a success status and will result in
11192      * the success callback being called. Any response status code outside of that range is
11193      * considered an error status and will result in the error callback being called.
11194      * Also, status codes less than -1 are normalized to zero. -1 usually means the request was
11195      * aborted, e.g. using a `config.timeout`.
11196      * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning
11197      * that the outcome (success or error) will be determined by the final response status code.
11198      *
11199      *
11200      * ## Shortcut methods
11201      *
11202      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
11203      * request data must be passed in for POST/PUT requests. An optional config can be passed as the
11204      * last argument.
11205      *
11206      * ```js
11207      *   $http.get('/someUrl', config).then(successCallback, errorCallback);
11208      *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
11209      * ```
11210      *
11211      * Complete list of shortcut methods:
11212      *
11213      * - {@link ng.$http#get $http.get}
11214      * - {@link ng.$http#head $http.head}
11215      * - {@link ng.$http#post $http.post}
11216      * - {@link ng.$http#put $http.put}
11217      * - {@link ng.$http#delete $http.delete}
11218      * - {@link ng.$http#jsonp $http.jsonp}
11219      * - {@link ng.$http#patch $http.patch}
11220      *
11221      *
11222      * ## Writing Unit Tests that use $http
11223      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
11224      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
11225      * request using trained responses.
11226      *
11227      * ```
11228      * $httpBackend.expectGET(...);
11229      * $http.get(...);
11230      * $httpBackend.flush();
11231      * ```
11232      *
11233      * ## Deprecation Notice
11234      * <div class="alert alert-danger">
11235      *   The `$http` legacy promise methods `success` and `error` have been deprecated and will be
11236      *   removed in v1.6.0.
11237      *   Use the standard `then` method instead.
11238      *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
11239      *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
11240      * </div>
11241      *
11242      * ## Setting HTTP Headers
11243      *
11244      * The $http service will automatically add certain HTTP headers to all requests. These defaults
11245      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
11246      * object, which currently contains this default configuration:
11247      *
11248      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
11249      *   - <code>Accept: application/json, text/plain, \*&#65279;/&#65279;\*</code>
11250      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
11251      *   - `Content-Type: application/json`
11252      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
11253      *   - `Content-Type: application/json`
11254      *
11255      * To add or overwrite these defaults, simply add or remove a property from these configuration
11256      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
11257      * with the lowercased HTTP method name as the key, e.g.
11258      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
11259      *
11260      * The defaults can also be set at runtime via the `$http.defaults` object in the same
11261      * fashion. For example:
11262      *
11263      * ```
11264      * module.run(function($http) {
11265      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
11266      * });
11267      * ```
11268      *
11269      * In addition, you can supply a `headers` property in the config object passed when
11270      * calling `$http(config)`, which overrides the defaults without changing them globally.
11271      *
11272      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
11273      * Use the `headers` property, setting the desired header to `undefined`. For example:
11274      *
11275      * ```js
11276      * var req = {
11277      *  method: 'POST',
11278      *  url: 'http://example.com',
11279      *  headers: {
11280      *    'Content-Type': undefined
11281      *  },
11282      *  data: { test: 'test' }
11283      * }
11284      *
11285      * $http(req).then(function(){...}, function(){...});
11286      * ```
11287      *
11288      * ## Transforming Requests and Responses
11289      *
11290      * Both requests and responses can be transformed using transformation functions: `transformRequest`
11291      * and `transformResponse`. These properties can be a single function that returns
11292      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
11293      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
11294      *
11295      * <div class="alert alert-warning">
11296      * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
11297      * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
11298      * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
11299      * function will be reflected on the scope and in any templates where the object is data-bound.
11300      * To prevent this, transform functions should have no side-effects.
11301      * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
11302      * </div>
11303      *
11304      * ### Default Transformations
11305      *
11306      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
11307      * `defaults.transformResponse` properties. If a request does not provide its own transformations
11308      * then these will be applied.
11309      *
11310      * You can augment or replace the default transformations by modifying these properties by adding to or
11311      * replacing the array.
11312      *
11313      * Angular provides the following default transformations:
11314      *
11315      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
11316      *
11317      * - If the `data` property of the request configuration object contains an object, serialize it
11318      *   into JSON format.
11319      *
11320      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
11321      *
11322      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
11323      *  - If JSON response is detected, deserialize it using a JSON parser.
11324      *
11325      *
11326      * ### Overriding the Default Transformations Per Request
11327      *
11328      * If you wish to override the request/response transformations only for a single request then provide
11329      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
11330      * into `$http`.
11331      *
11332      * Note that if you provide these properties on the config object the default transformations will be
11333      * overwritten. If you wish to augment the default transformations then you must include them in your
11334      * local transformation array.
11335      *
11336      * The following code demonstrates adding a new response transformation to be run after the default response
11337      * transformations have been run.
11338      *
11339      * ```js
11340      * function appendTransform(defaults, transform) {
11341      *
11342      *   // We can't guarantee that the default transformation is an array
11343      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
11344      *
11345      *   // Append the new transformation to the defaults
11346      *   return defaults.concat(transform);
11347      * }
11348      *
11349      * $http({
11350      *   url: '...',
11351      *   method: 'GET',
11352      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
11353      *     return doTransform(value);
11354      *   })
11355      * });
11356      * ```
11357      *
11358      *
11359      * ## Caching
11360      *
11361      * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
11362      * set the config.cache value or the default cache value to TRUE or to a cache object (created
11363      * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
11364      * precedence over the default cache value.
11365      *
11366      * In order to:
11367      *   * cache all responses - set the default cache value to TRUE or to a cache object
11368      *   * cache a specific response - set config.cache value to TRUE or to a cache object
11369      *
11370      * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
11371      * then the default `$cacheFactory("$http")` object is used.
11372      *
11373      * The default cache value can be set by updating the
11374      * {@link ng.$http#defaults `$http.defaults.cache`} property or the
11375      * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
11376      *
11377      * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
11378      * the relevant cache object. The next time the same request is made, the response is returned
11379      * from the cache without sending a request to the server.
11380      *
11381      * Take note that:
11382      *
11383      *   * Only GET and JSONP requests are cached.
11384      *   * The cache key is the request URL including search parameters; headers are not considered.
11385      *   * Cached responses are returned asynchronously, in the same way as responses from the server.
11386      *   * If multiple identical requests are made using the same cache, which is not yet populated,
11387      *     one request will be made to the server and remaining requests will return the same response.
11388      *   * A cache-control header on the response does not affect if or how responses are cached.
11389      *
11390      *
11391      * ## Interceptors
11392      *
11393      * Before you start creating interceptors, be sure to understand the
11394      * {@link ng.$q $q and deferred/promise APIs}.
11395      *
11396      * For purposes of global error handling, authentication, or any kind of synchronous or
11397      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
11398      * able to intercept requests before they are handed to the server and
11399      * responses before they are handed over to the application code that
11400      * initiated these requests. The interceptors leverage the {@link ng.$q
11401      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
11402      *
11403      * The interceptors are service factories that are registered with the `$httpProvider` by
11404      * adding them to the `$httpProvider.interceptors` array. The factory is called and
11405      * injected with dependencies (if specified) and returns the interceptor.
11406      *
11407      * There are two kinds of interceptors (and two kinds of rejection interceptors):
11408      *
11409      *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
11410      *     modify the `config` object or create a new one. The function needs to return the `config`
11411      *     object directly, or a promise containing the `config` or a new `config` object.
11412      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
11413      *     resolved with a rejection.
11414      *   * `response`: interceptors get called with http `response` object. The function is free to
11415      *     modify the `response` object or create a new one. The function needs to return the `response`
11416      *     object directly, or as a promise containing the `response` or a new `response` object.
11417      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
11418      *     resolved with a rejection.
11419      *
11420      *
11421      * ```js
11422      *   // register the interceptor as a service
11423      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
11424      *     return {
11425      *       // optional method
11426      *       'request': function(config) {
11427      *         // do something on success
11428      *         return config;
11429      *       },
11430      *
11431      *       // optional method
11432      *      'requestError': function(rejection) {
11433      *         // do something on error
11434      *         if (canRecover(rejection)) {
11435      *           return responseOrNewPromise
11436      *         }
11437      *         return $q.reject(rejection);
11438      *       },
11439      *
11440      *
11441      *
11442      *       // optional method
11443      *       'response': function(response) {
11444      *         // do something on success
11445      *         return response;
11446      *       },
11447      *
11448      *       // optional method
11449      *      'responseError': function(rejection) {
11450      *         // do something on error
11451      *         if (canRecover(rejection)) {
11452      *           return responseOrNewPromise
11453      *         }
11454      *         return $q.reject(rejection);
11455      *       }
11456      *     };
11457      *   });
11458      *
11459      *   $httpProvider.interceptors.push('myHttpInterceptor');
11460      *
11461      *
11462      *   // alternatively, register the interceptor via an anonymous factory
11463      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
11464      *     return {
11465      *      'request': function(config) {
11466      *          // same as above
11467      *       },
11468      *
11469      *       'response': function(response) {
11470      *          // same as above
11471      *       }
11472      *     };
11473      *   });
11474      * ```
11475      *
11476      * ## Security Considerations
11477      *
11478      * When designing web applications, consider security threats from:
11479      *
11480      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
11481      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
11482      *
11483      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
11484      * pre-configured with strategies that address these issues, but for this to work backend server
11485      * cooperation is required.
11486      *
11487      * ### JSON Vulnerability Protection
11488      *
11489      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
11490      * allows third party website to turn your JSON resource URL into
11491      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
11492      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
11493      * Angular will automatically strip the prefix before processing it as JSON.
11494      *
11495      * For example if your server needs to return:
11496      * ```js
11497      * ['one','two']
11498      * ```
11499      *
11500      * which is vulnerable to attack, your server can return:
11501      * ```js
11502      * )]}',
11503      * ['one','two']
11504      * ```
11505      *
11506      * Angular will strip the prefix, before processing the JSON.
11507      *
11508      *
11509      * ### Cross Site Request Forgery (XSRF) Protection
11510      *
11511      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
11512      * which the attacker can trick an authenticated user into unknowingly executing actions on your
11513      * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
11514      * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
11515      * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
11516      * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
11517      * The header will not be set for cross-domain requests.
11518      *
11519      * To take advantage of this, your server needs to set a token in a JavaScript readable session
11520      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
11521      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
11522      * that only JavaScript running on your domain could have sent the request. The token must be
11523      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
11524      * making up its own tokens). We recommend that the token is a digest of your site's
11525      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
11526      * for added security.
11527      *
11528      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
11529      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
11530      * or the per-request config object.
11531      *
11532      * In order to prevent collisions in environments where multiple Angular apps share the
11533      * same domain or subdomain, we recommend that each application uses unique cookie name.
11534      *
11535      * @param {object} config Object describing the request to be made and how it should be
11536      *    processed. The object has following properties:
11537      *
11538      *    - **method** â€“ `{string}` â€“ HTTP method (e.g. 'GET', 'POST', etc)
11539      *    - **url** â€“ `{string}` â€“ Absolute or relative URL of the resource that is being requested.
11540      *    - **params** â€“ `{Object.<string|Object>}` â€“ Map of strings or objects which will be serialized
11541      *      with the `paramSerializer` and appended as GET parameters.
11542      *    - **data** â€“ `{string|Object}` â€“ Data to be sent as the request message data.
11543      *    - **headers** â€“ `{Object}` â€“ Map of strings or functions which return strings representing
11544      *      HTTP headers to send to the server. If the return value of a function is null, the
11545      *      header will not be sent. Functions accept a config object as an argument.
11546      *    - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
11547      *      To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
11548      *      The handler will be called in the context of a `$apply` block.
11549      *    - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
11550      *      object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
11551      *      The handler will be called in the context of a `$apply` block.
11552      *    - **xsrfHeaderName** â€“ `{string}` â€“ Name of HTTP header to populate with the XSRF token.
11553      *    - **xsrfCookieName** â€“ `{string}` â€“ Name of cookie containing the XSRF token.
11554      *    - **transformRequest** â€“
11555      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` â€“
11556      *      transform function or an array of such functions. The transform function takes the http
11557      *      request body and headers and returns its transformed (typically serialized) version.
11558      *      See {@link ng.$http#overriding-the-default-transformations-per-request
11559      *      Overriding the Default Transformations}
11560      *    - **transformResponse** â€“
11561      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` â€“
11562      *      transform function or an array of such functions. The transform function takes the http
11563      *      response body, headers and status and returns its transformed (typically deserialized) version.
11564      *      See {@link ng.$http#overriding-the-default-transformations-per-request
11565      *      Overriding the Default Transformations}
11566      *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
11567      *      prepare the string representation of request parameters (specified as an object).
11568      *      If specified as string, it is interpreted as function registered with the
11569      *      {@link $injector $injector}, which means you can create your own serializer
11570      *      by registering it as a {@link auto.$provide#service service}.
11571      *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
11572      *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
11573      *    - **cache** â€“ `{boolean|Object}` â€“ A boolean value or object created with
11574      *      {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
11575      *      See {@link $http#caching $http Caching} for more information.
11576      *    - **timeout** â€“ `{number|Promise}` â€“ timeout in milliseconds, or {@link ng.$q promise}
11577      *      that should abort the request when resolved.
11578      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
11579      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
11580      *      for more information.
11581      *    - **responseType** - `{string}` - see
11582      *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
11583      *
11584      * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
11585      *                        when the request succeeds or fails.
11586      *
11587      *
11588      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
11589      *   requests. This is primarily meant to be used for debugging purposes.
11590      *
11591      *
11592      * @example
11593 <example module="httpExample" name="http-service">
11594 <file name="index.html">
11595   <div ng-controller="FetchController">
11596     <select ng-model="method" aria-label="Request method">
11597       <option>GET</option>
11598       <option>JSONP</option>
11599     </select>
11600     <input type="text" ng-model="url" size="80" aria-label="URL" />
11601     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
11602     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
11603     <button id="samplejsonpbtn"
11604       ng-click="updateModel('JSONP',
11605                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
11606       Sample JSONP
11607     </button>
11608     <button id="invalidjsonpbtn"
11609       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
11610         Invalid JSONP
11611       </button>
11612     <pre>http status code: {{status}}</pre>
11613     <pre>http response data: {{data}}</pre>
11614   </div>
11615 </file>
11616 <file name="script.js">
11617   angular.module('httpExample', [])
11618     .controller('FetchController', ['$scope', '$http', '$templateCache',
11619       function($scope, $http, $templateCache) {
11620         $scope.method = 'GET';
11621         $scope.url = 'http-hello.html';
11622
11623         $scope.fetch = function() {
11624           $scope.code = null;
11625           $scope.response = null;
11626
11627           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
11628             then(function(response) {
11629               $scope.status = response.status;
11630               $scope.data = response.data;
11631             }, function(response) {
11632               $scope.data = response.data || 'Request failed';
11633               $scope.status = response.status;
11634           });
11635         };
11636
11637         $scope.updateModel = function(method, url) {
11638           $scope.method = method;
11639           $scope.url = url;
11640         };
11641       }]);
11642 </file>
11643 <file name="http-hello.html">
11644   Hello, $http!
11645 </file>
11646 <file name="protractor.js" type="protractor">
11647   var status = element(by.binding('status'));
11648   var data = element(by.binding('data'));
11649   var fetchBtn = element(by.id('fetchbtn'));
11650   var sampleGetBtn = element(by.id('samplegetbtn'));
11651   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
11652
11653   it('should make an xhr GET request', function() {
11654     sampleGetBtn.click();
11655     fetchBtn.click();
11656     expect(status.getText()).toMatch('200');
11657     expect(data.getText()).toMatch(/Hello, \$http!/);
11658   });
11659
11660 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
11661 // it('should make a JSONP request to angularjs.org', function() {
11662 //   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
11663 //   sampleJsonpBtn.click();
11664 //   fetchBtn.click();
11665 //   expect(status.getText()).toMatch('200');
11666 //   expect(data.getText()).toMatch(/Super Hero!/);
11667 // });
11668
11669   it('should make JSONP request to invalid URL and invoke the error handler',
11670       function() {
11671     invalidJsonpBtn.click();
11672     fetchBtn.click();
11673     expect(status.getText()).toMatch('0');
11674     expect(data.getText()).toMatch('Request failed');
11675   });
11676 </file>
11677 </example>
11678      */
11679     function $http(requestConfig) {
11680
11681       if (!isObject(requestConfig)) {
11682         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
11683       }
11684
11685       if (!isString(requestConfig.url)) {
11686         throw minErr('$http')('badreq', 'Http request configuration url must be a string.  Received: {0}', requestConfig.url);
11687       }
11688
11689       var config = extend({
11690         method: 'get',
11691         transformRequest: defaults.transformRequest,
11692         transformResponse: defaults.transformResponse,
11693         paramSerializer: defaults.paramSerializer
11694       }, requestConfig);
11695
11696       config.headers = mergeHeaders(requestConfig);
11697       config.method = uppercase(config.method);
11698       config.paramSerializer = isString(config.paramSerializer) ?
11699           $injector.get(config.paramSerializer) : config.paramSerializer;
11700
11701       var requestInterceptors = [];
11702       var responseInterceptors = [];
11703       var promise = $q.when(config);
11704
11705       // apply interceptors
11706       forEach(reversedInterceptors, function(interceptor) {
11707         if (interceptor.request || interceptor.requestError) {
11708           requestInterceptors.unshift(interceptor.request, interceptor.requestError);
11709         }
11710         if (interceptor.response || interceptor.responseError) {
11711           responseInterceptors.push(interceptor.response, interceptor.responseError);
11712         }
11713       });
11714
11715       promise = chainInterceptors(promise, requestInterceptors);
11716       promise = promise.then(serverRequest);
11717       promise = chainInterceptors(promise, responseInterceptors);
11718
11719       if (useLegacyPromise) {
11720         promise.success = function(fn) {
11721           assertArgFn(fn, 'fn');
11722
11723           promise.then(function(response) {
11724             fn(response.data, response.status, response.headers, config);
11725           });
11726           return promise;
11727         };
11728
11729         promise.error = function(fn) {
11730           assertArgFn(fn, 'fn');
11731
11732           promise.then(null, function(response) {
11733             fn(response.data, response.status, response.headers, config);
11734           });
11735           return promise;
11736         };
11737       } else {
11738         promise.success = $httpMinErrLegacyFn('success');
11739         promise.error = $httpMinErrLegacyFn('error');
11740       }
11741
11742       return promise;
11743
11744
11745       function chainInterceptors(promise, interceptors) {
11746         for (var i = 0, ii = interceptors.length; i < ii;) {
11747           var thenFn = interceptors[i++];
11748           var rejectFn = interceptors[i++];
11749
11750           promise = promise.then(thenFn, rejectFn);
11751         }
11752
11753         interceptors.length = 0;
11754
11755         return promise;
11756       }
11757
11758       function executeHeaderFns(headers, config) {
11759         var headerContent, processedHeaders = {};
11760
11761         forEach(headers, function(headerFn, header) {
11762           if (isFunction(headerFn)) {
11763             headerContent = headerFn(config);
11764             if (headerContent != null) {
11765               processedHeaders[header] = headerContent;
11766             }
11767           } else {
11768             processedHeaders[header] = headerFn;
11769           }
11770         });
11771
11772         return processedHeaders;
11773       }
11774
11775       function mergeHeaders(config) {
11776         var defHeaders = defaults.headers,
11777             reqHeaders = extend({}, config.headers),
11778             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
11779
11780         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
11781
11782         // using for-in instead of forEach to avoid unnecessary iteration after header has been found
11783         defaultHeadersIteration:
11784         for (defHeaderName in defHeaders) {
11785           lowercaseDefHeaderName = lowercase(defHeaderName);
11786
11787           for (reqHeaderName in reqHeaders) {
11788             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
11789               continue defaultHeadersIteration;
11790             }
11791           }
11792
11793           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
11794         }
11795
11796         // execute if header value is a function for merged headers
11797         return executeHeaderFns(reqHeaders, shallowCopy(config));
11798       }
11799
11800       function serverRequest(config) {
11801         var headers = config.headers;
11802         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
11803
11804         // strip content-type if data is undefined
11805         if (isUndefined(reqData)) {
11806           forEach(headers, function(value, header) {
11807             if (lowercase(header) === 'content-type') {
11808               delete headers[header];
11809             }
11810           });
11811         }
11812
11813         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
11814           config.withCredentials = defaults.withCredentials;
11815         }
11816
11817         // send request
11818         return sendReq(config, reqData).then(transformResponse, transformResponse);
11819       }
11820
11821       function transformResponse(response) {
11822         // make a copy since the response must be cacheable
11823         var resp = extend({}, response);
11824         resp.data = transformData(response.data, response.headers, response.status,
11825                                   config.transformResponse);
11826         return (isSuccess(response.status))
11827           ? resp
11828           : $q.reject(resp);
11829       }
11830     }
11831
11832     $http.pendingRequests = [];
11833
11834     /**
11835      * @ngdoc method
11836      * @name $http#get
11837      *
11838      * @description
11839      * Shortcut method to perform `GET` request.
11840      *
11841      * @param {string} url Relative or absolute URL specifying the destination of the request
11842      * @param {Object=} config Optional configuration object
11843      * @returns {HttpPromise} Future object
11844      */
11845
11846     /**
11847      * @ngdoc method
11848      * @name $http#delete
11849      *
11850      * @description
11851      * Shortcut method to perform `DELETE` request.
11852      *
11853      * @param {string} url Relative or absolute URL specifying the destination of the request
11854      * @param {Object=} config Optional configuration object
11855      * @returns {HttpPromise} Future object
11856      */
11857
11858     /**
11859      * @ngdoc method
11860      * @name $http#head
11861      *
11862      * @description
11863      * Shortcut method to perform `HEAD` request.
11864      *
11865      * @param {string} url Relative or absolute URL specifying the destination of the request
11866      * @param {Object=} config Optional configuration object
11867      * @returns {HttpPromise} Future object
11868      */
11869
11870     /**
11871      * @ngdoc method
11872      * @name $http#jsonp
11873      *
11874      * @description
11875      * Shortcut method to perform `JSONP` request.
11876      * If you would like to customize where and how the callbacks are stored then try overriding
11877      * or decorating the {@link $jsonpCallbacks} service.
11878      *
11879      * @param {string} url Relative or absolute URL specifying the destination of the request.
11880      *                     The name of the callback should be the string `JSON_CALLBACK`.
11881      * @param {Object=} config Optional configuration object
11882      * @returns {HttpPromise} Future object
11883      */
11884     createShortMethods('get', 'delete', 'head', 'jsonp');
11885
11886     /**
11887      * @ngdoc method
11888      * @name $http#post
11889      *
11890      * @description
11891      * Shortcut method to perform `POST` request.
11892      *
11893      * @param {string} url Relative or absolute URL specifying the destination of the request
11894      * @param {*} data Request content
11895      * @param {Object=} config Optional configuration object
11896      * @returns {HttpPromise} Future object
11897      */
11898
11899     /**
11900      * @ngdoc method
11901      * @name $http#put
11902      *
11903      * @description
11904      * Shortcut method to perform `PUT` request.
11905      *
11906      * @param {string} url Relative or absolute URL specifying the destination of the request
11907      * @param {*} data Request content
11908      * @param {Object=} config Optional configuration object
11909      * @returns {HttpPromise} Future object
11910      */
11911
11912      /**
11913       * @ngdoc method
11914       * @name $http#patch
11915       *
11916       * @description
11917       * Shortcut method to perform `PATCH` request.
11918       *
11919       * @param {string} url Relative or absolute URL specifying the destination of the request
11920       * @param {*} data Request content
11921       * @param {Object=} config Optional configuration object
11922       * @returns {HttpPromise} Future object
11923       */
11924     createShortMethodsWithData('post', 'put', 'patch');
11925
11926         /**
11927          * @ngdoc property
11928          * @name $http#defaults
11929          *
11930          * @description
11931          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
11932          * default headers, withCredentials as well as request and response transformations.
11933          *
11934          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
11935          */
11936     $http.defaults = defaults;
11937
11938
11939     return $http;
11940
11941
11942     function createShortMethods(names) {
11943       forEach(arguments, function(name) {
11944         $http[name] = function(url, config) {
11945           return $http(extend({}, config || {}, {
11946             method: name,
11947             url: url
11948           }));
11949         };
11950       });
11951     }
11952
11953
11954     function createShortMethodsWithData(name) {
11955       forEach(arguments, function(name) {
11956         $http[name] = function(url, data, config) {
11957           return $http(extend({}, config || {}, {
11958             method: name,
11959             url: url,
11960             data: data
11961           }));
11962         };
11963       });
11964     }
11965
11966
11967     /**
11968      * Makes the request.
11969      *
11970      * !!! ACCESSES CLOSURE VARS:
11971      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
11972      */
11973     function sendReq(config, reqData) {
11974       var deferred = $q.defer(),
11975           promise = deferred.promise,
11976           cache,
11977           cachedResp,
11978           reqHeaders = config.headers,
11979           url = buildUrl(config.url, config.paramSerializer(config.params));
11980
11981       $http.pendingRequests.push(config);
11982       promise.then(removePendingReq, removePendingReq);
11983
11984
11985       if ((config.cache || defaults.cache) && config.cache !== false &&
11986           (config.method === 'GET' || config.method === 'JSONP')) {
11987         cache = isObject(config.cache) ? config.cache
11988               : isObject(defaults.cache) ? defaults.cache
11989               : defaultCache;
11990       }
11991
11992       if (cache) {
11993         cachedResp = cache.get(url);
11994         if (isDefined(cachedResp)) {
11995           if (isPromiseLike(cachedResp)) {
11996             // cached request has already been sent, but there is no response yet
11997             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
11998           } else {
11999             // serving from cache
12000             if (isArray(cachedResp)) {
12001               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
12002             } else {
12003               resolvePromise(cachedResp, 200, {}, 'OK');
12004             }
12005           }
12006         } else {
12007           // put the promise for the non-transformed response into cache as a placeholder
12008           cache.put(url, promise);
12009         }
12010       }
12011
12012
12013       // if we won't have the response in cache, set the xsrf headers and
12014       // send the request to the backend
12015       if (isUndefined(cachedResp)) {
12016         var xsrfValue = urlIsSameOrigin(config.url)
12017             ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
12018             : undefined;
12019         if (xsrfValue) {
12020           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
12021         }
12022
12023         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
12024             config.withCredentials, config.responseType,
12025             createApplyHandlers(config.eventHandlers),
12026             createApplyHandlers(config.uploadEventHandlers));
12027       }
12028
12029       return promise;
12030
12031       function createApplyHandlers(eventHandlers) {
12032         if (eventHandlers) {
12033           var applyHandlers = {};
12034           forEach(eventHandlers, function(eventHandler, key) {
12035             applyHandlers[key] = function(event) {
12036               if (useApplyAsync) {
12037                 $rootScope.$applyAsync(callEventHandler);
12038               } else if ($rootScope.$$phase) {
12039                 callEventHandler();
12040               } else {
12041                 $rootScope.$apply(callEventHandler);
12042               }
12043
12044               function callEventHandler() {
12045                 eventHandler(event);
12046               }
12047             };
12048           });
12049           return applyHandlers;
12050         }
12051       }
12052
12053
12054       /**
12055        * Callback registered to $httpBackend():
12056        *  - caches the response if desired
12057        *  - resolves the raw $http promise
12058        *  - calls $apply
12059        */
12060       function done(status, response, headersString, statusText) {
12061         if (cache) {
12062           if (isSuccess(status)) {
12063             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
12064           } else {
12065             // remove promise from the cache
12066             cache.remove(url);
12067           }
12068         }
12069
12070         function resolveHttpPromise() {
12071           resolvePromise(response, status, headersString, statusText);
12072         }
12073
12074         if (useApplyAsync) {
12075           $rootScope.$applyAsync(resolveHttpPromise);
12076         } else {
12077           resolveHttpPromise();
12078           if (!$rootScope.$$phase) $rootScope.$apply();
12079         }
12080       }
12081
12082
12083       /**
12084        * Resolves the raw $http promise.
12085        */
12086       function resolvePromise(response, status, headers, statusText) {
12087         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
12088         status = status >= -1 ? status : 0;
12089
12090         (isSuccess(status) ? deferred.resolve : deferred.reject)({
12091           data: response,
12092           status: status,
12093           headers: headersGetter(headers),
12094           config: config,
12095           statusText: statusText
12096         });
12097       }
12098
12099       function resolvePromiseWithResult(result) {
12100         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
12101       }
12102
12103       function removePendingReq() {
12104         var idx = $http.pendingRequests.indexOf(config);
12105         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
12106       }
12107     }
12108
12109
12110     function buildUrl(url, serializedParams) {
12111       if (serializedParams.length > 0) {
12112         url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams;
12113       }
12114       return url;
12115     }
12116   }];
12117 }
12118
12119 /**
12120  * @ngdoc service
12121  * @name $xhrFactory
12122  * @this
12123  *
12124  * @description
12125  * Factory function used to create XMLHttpRequest objects.
12126  *
12127  * Replace or decorate this service to create your own custom XMLHttpRequest objects.
12128  *
12129  * ```
12130  * angular.module('myApp', [])
12131  * .factory('$xhrFactory', function() {
12132  *   return function createXhr(method, url) {
12133  *     return new window.XMLHttpRequest({mozSystem: true});
12134  *   };
12135  * });
12136  * ```
12137  *
12138  * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
12139  * @param {string} url URL of the request.
12140  */
12141 function $xhrFactoryProvider() {
12142   this.$get = function() {
12143     return function createXhr() {
12144       return new window.XMLHttpRequest();
12145     };
12146   };
12147 }
12148
12149 /**
12150  * @ngdoc service
12151  * @name $httpBackend
12152  * @requires $jsonpCallbacks
12153  * @requires $document
12154  * @requires $xhrFactory
12155  * @this
12156  *
12157  * @description
12158  * HTTP backend used by the {@link ng.$http service} that delegates to
12159  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
12160  *
12161  * You should never need to use this service directly, instead use the higher-level abstractions:
12162  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
12163  *
12164  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
12165  * $httpBackend} which can be trained with responses.
12166  */
12167 function $HttpBackendProvider() {
12168   this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {
12169     return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);
12170   }];
12171 }
12172
12173 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
12174   // TODO(vojta): fix the signature
12175   return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
12176     $browser.$$incOutstandingRequestCount();
12177     url = url || $browser.url();
12178
12179     if (lowercase(method) === 'jsonp') {
12180       var callbackPath = callbacks.createCallback(url);
12181       var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {
12182         // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)
12183         var response = (status === 200) && callbacks.getResponse(callbackPath);
12184         completeRequest(callback, status, response, '', text);
12185         callbacks.removeCallback(callbackPath);
12186       });
12187     } else {
12188
12189       var xhr = createXhr(method, url);
12190
12191       xhr.open(method, url, true);
12192       forEach(headers, function(value, key) {
12193         if (isDefined(value)) {
12194             xhr.setRequestHeader(key, value);
12195         }
12196       });
12197
12198       xhr.onload = function requestLoaded() {
12199         var statusText = xhr.statusText || '';
12200
12201         // responseText is the old-school way of retrieving response (supported by IE9)
12202         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
12203         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
12204
12205         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
12206         var status = xhr.status === 1223 ? 204 : xhr.status;
12207
12208         // fix status code when it is 0 (0 status is undocumented).
12209         // Occurs when accessing file resources or on Android 4.1 stock browser
12210         // while retrieving files from application cache.
12211         if (status === 0) {
12212           status = response ? 200 : urlResolve(url).protocol === 'file' ? 404 : 0;
12213         }
12214
12215         completeRequest(callback,
12216             status,
12217             response,
12218             xhr.getAllResponseHeaders(),
12219             statusText);
12220       };
12221
12222       var requestError = function() {
12223         // The response is always empty
12224         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
12225         completeRequest(callback, -1, null, null, '');
12226       };
12227
12228       xhr.onerror = requestError;
12229       xhr.onabort = requestError;
12230       xhr.ontimeout = requestError;
12231
12232       forEach(eventHandlers, function(value, key) {
12233           xhr.addEventListener(key, value);
12234       });
12235
12236       forEach(uploadEventHandlers, function(value, key) {
12237         xhr.upload.addEventListener(key, value);
12238       });
12239
12240       if (withCredentials) {
12241         xhr.withCredentials = true;
12242       }
12243
12244       if (responseType) {
12245         try {
12246           xhr.responseType = responseType;
12247         } catch (e) {
12248           // WebKit added support for the json responseType value on 09/03/2013
12249           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
12250           // known to throw when setting the value "json" as the response type. Other older
12251           // browsers implementing the responseType
12252           //
12253           // The json response type can be ignored if not supported, because JSON payloads are
12254           // parsed on the client-side regardless.
12255           if (responseType !== 'json') {
12256             throw e;
12257           }
12258         }
12259       }
12260
12261       xhr.send(isUndefined(post) ? null : post);
12262     }
12263
12264     if (timeout > 0) {
12265       var timeoutId = $browserDefer(timeoutRequest, timeout);
12266     } else if (isPromiseLike(timeout)) {
12267       timeout.then(timeoutRequest);
12268     }
12269
12270
12271     function timeoutRequest() {
12272       if (jsonpDone) {
12273         jsonpDone();
12274       }
12275       if (xhr) {
12276         xhr.abort();
12277       }
12278     }
12279
12280     function completeRequest(callback, status, response, headersString, statusText) {
12281       // cancel timeout and subsequent timeout promise resolution
12282       if (isDefined(timeoutId)) {
12283         $browserDefer.cancel(timeoutId);
12284       }
12285       jsonpDone = xhr = null;
12286
12287       callback(status, response, headersString, statusText);
12288       $browser.$$completeOutstandingRequest(noop);
12289     }
12290   };
12291
12292   function jsonpReq(url, callbackPath, done) {
12293     url = url.replace('JSON_CALLBACK', callbackPath);
12294     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
12295     // - fetches local scripts via XHR and evals them
12296     // - adds and immediately removes script elements from the document
12297     var script = rawDocument.createElement('script'), callback = null;
12298     script.type = 'text/javascript';
12299     script.src = url;
12300     script.async = true;
12301
12302     callback = function(event) {
12303       removeEventListenerFn(script, 'load', callback);
12304       removeEventListenerFn(script, 'error', callback);
12305       rawDocument.body.removeChild(script);
12306       script = null;
12307       var status = -1;
12308       var text = 'unknown';
12309
12310       if (event) {
12311         if (event.type === 'load' && !callbacks.wasCalled(callbackPath)) {
12312           event = { type: 'error' };
12313         }
12314         text = event.type;
12315         status = event.type === 'error' ? 404 : 200;
12316       }
12317
12318       if (done) {
12319         done(status, text);
12320       }
12321     };
12322
12323     addEventListenerFn(script, 'load', callback);
12324     addEventListenerFn(script, 'error', callback);
12325     rawDocument.body.appendChild(script);
12326     return callback;
12327   }
12328 }
12329
12330 var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
12331 $interpolateMinErr.throwNoconcat = function(text) {
12332   throw $interpolateMinErr('noconcat',
12333       'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' +
12334       'interpolations that concatenate multiple expressions when a trusted value is ' +
12335       'required.  See http://docs.angularjs.org/api/ng.$sce', text);
12336 };
12337
12338 $interpolateMinErr.interr = function(text, err) {
12339   return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString());
12340 };
12341
12342 /**
12343  * @ngdoc provider
12344  * @name $interpolateProvider
12345  * @this
12346  *
12347  * @description
12348  *
12349  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
12350  *
12351  * <div class="alert alert-danger">
12352  * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
12353  * template within a Python Jinja template (or any other template language). Mixing templating
12354  * languages is **very dangerous**. The embedding template language will not safely escape Angular
12355  * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
12356  * security bugs!
12357  * </div>
12358  *
12359  * @example
12360 <example name="custom-interpolation-markup" module="customInterpolationApp">
12361 <file name="index.html">
12362 <script>
12363   var customInterpolationApp = angular.module('customInterpolationApp', []);
12364
12365   customInterpolationApp.config(function($interpolateProvider) {
12366     $interpolateProvider.startSymbol('//');
12367     $interpolateProvider.endSymbol('//');
12368   });
12369
12370
12371   customInterpolationApp.controller('DemoController', function() {
12372       this.label = "This binding is brought you by // interpolation symbols.";
12373   });
12374 </script>
12375 <div ng-controller="DemoController as demo">
12376     //demo.label//
12377 </div>
12378 </file>
12379 <file name="protractor.js" type="protractor">
12380   it('should interpolate binding with custom symbols', function() {
12381     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
12382   });
12383 </file>
12384 </example>
12385  */
12386 function $InterpolateProvider() {
12387   var startSymbol = '{{';
12388   var endSymbol = '}}';
12389
12390   /**
12391    * @ngdoc method
12392    * @name $interpolateProvider#startSymbol
12393    * @description
12394    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
12395    *
12396    * @param {string=} value new value to set the starting symbol to.
12397    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
12398    */
12399   this.startSymbol = function(value) {
12400     if (value) {
12401       startSymbol = value;
12402       return this;
12403     } else {
12404       return startSymbol;
12405     }
12406   };
12407
12408   /**
12409    * @ngdoc method
12410    * @name $interpolateProvider#endSymbol
12411    * @description
12412    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
12413    *
12414    * @param {string=} value new value to set the ending symbol to.
12415    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
12416    */
12417   this.endSymbol = function(value) {
12418     if (value) {
12419       endSymbol = value;
12420       return this;
12421     } else {
12422       return endSymbol;
12423     }
12424   };
12425
12426
12427   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
12428     var startSymbolLength = startSymbol.length,
12429         endSymbolLength = endSymbol.length,
12430         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
12431         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
12432
12433     function escape(ch) {
12434       return '\\\\\\' + ch;
12435     }
12436
12437     function unescapeText(text) {
12438       return text.replace(escapedStartRegexp, startSymbol).
12439         replace(escapedEndRegexp, endSymbol);
12440     }
12441
12442     function stringify(value) {
12443       if (value == null) { // null || undefined
12444         return '';
12445       }
12446       switch (typeof value) {
12447         case 'string':
12448           break;
12449         case 'number':
12450           value = '' + value;
12451           break;
12452         default:
12453           value = toJson(value);
12454       }
12455
12456       return value;
12457     }
12458
12459     // TODO: this is the same as the constantWatchDelegate in parse.js
12460     function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
12461       var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
12462         unwatch();
12463         return constantInterp(scope);
12464       }, listener, objectEquality);
12465       return unwatch;
12466     }
12467
12468     /**
12469      * @ngdoc service
12470      * @name $interpolate
12471      * @kind function
12472      *
12473      * @requires $parse
12474      * @requires $sce
12475      *
12476      * @description
12477      *
12478      * Compiles a string with markup into an interpolation function. This service is used by the
12479      * HTML {@link ng.$compile $compile} service for data binding. See
12480      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
12481      * interpolation markup.
12482      *
12483      *
12484      * ```js
12485      *   var $interpolate = ...; // injected
12486      *   var exp = $interpolate('Hello {{name | uppercase}}!');
12487      *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
12488      * ```
12489      *
12490      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
12491      * `true`, the interpolation function will return `undefined` unless all embedded expressions
12492      * evaluate to a value other than `undefined`.
12493      *
12494      * ```js
12495      *   var $interpolate = ...; // injected
12496      *   var context = {greeting: 'Hello', name: undefined };
12497      *
12498      *   // default "forgiving" mode
12499      *   var exp = $interpolate('{{greeting}} {{name}}!');
12500      *   expect(exp(context)).toEqual('Hello !');
12501      *
12502      *   // "allOrNothing" mode
12503      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
12504      *   expect(exp(context)).toBeUndefined();
12505      *   context.name = 'Angular';
12506      *   expect(exp(context)).toEqual('Hello Angular!');
12507      * ```
12508      *
12509      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
12510      *
12511      * #### Escaped Interpolation
12512      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
12513      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
12514      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
12515      * or binding.
12516      *
12517      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
12518      * degree, while also enabling code examples to work without relying on the
12519      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
12520      *
12521      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
12522      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
12523      * interpolation start/end markers with their escaped counterparts.**
12524      *
12525      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
12526      * output when the $interpolate service processes the text. So, for HTML elements interpolated
12527      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
12528      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
12529      * this is typically useful only when user-data is used in rendering a template from the server, or
12530      * when otherwise untrusted data is used by a directive.
12531      *
12532      * <example name="interpolation">
12533      *  <file name="index.html">
12534      *    <div ng-init="username='A user'">
12535      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
12536      *        </p>
12537      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
12538      *        application, but fails to accomplish their task, because the server has correctly
12539      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
12540      *        characters.</p>
12541      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
12542      *        from the database by an administrator.</p>
12543      *    </div>
12544      *  </file>
12545      * </example>
12546      *
12547      * @knownIssue
12548      * It is currently not possible for an interpolated expression to contain the interpolation end
12549      * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
12550      * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
12551      *
12552      * @knownIssue
12553      * All directives and components must use the standard `{{` `}}` interpolation symbols
12554      * in their templates. If you change the application interpolation symbols the {@link $compile}
12555      * service will attempt to denormalize the standard symbols to the custom symbols.
12556      * The denormalization process is not clever enough to know not to replace instances of the standard
12557      * symbols where they would not normally be treated as interpolation symbols. For example in the following
12558      * code snippet the closing braces of the literal object will get incorrectly denormalized:
12559      *
12560      * ```
12561      * <div data-context='{"context":{"id":3,"type":"page"}}">
12562      * ```
12563      *
12564      * The workaround is to ensure that such instances are separated by whitespace:
12565      * ```
12566      * <div data-context='{"context":{"id":3,"type":"page"} }">
12567      * ```
12568      *
12569      * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.
12570      *
12571      * @param {string} text The text with markup to interpolate.
12572      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
12573      *    embedded expression in order to return an interpolation function. Strings with no
12574      *    embedded expression will return null for the interpolation function.
12575      * @param {string=} trustedContext when provided, the returned function passes the interpolated
12576      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
12577      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
12578      *    provides Strict Contextual Escaping for details.
12579      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
12580      *    unless all embedded expressions evaluate to a value other than `undefined`.
12581      * @returns {function(context)} an interpolation function which is used to compute the
12582      *    interpolated string. The function has these parameters:
12583      *
12584      * - `context`: evaluation context for all expressions embedded in the interpolated text
12585      */
12586     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
12587       // Provide a quick exit and simplified result function for text with no interpolation
12588       if (!text.length || text.indexOf(startSymbol) === -1) {
12589         var constantInterp;
12590         if (!mustHaveExpression) {
12591           var unescapedText = unescapeText(text);
12592           constantInterp = valueFn(unescapedText);
12593           constantInterp.exp = text;
12594           constantInterp.expressions = [];
12595           constantInterp.$$watchDelegate = constantWatchDelegate;
12596         }
12597         return constantInterp;
12598       }
12599
12600       allOrNothing = !!allOrNothing;
12601       var startIndex,
12602           endIndex,
12603           index = 0,
12604           expressions = [],
12605           parseFns = [],
12606           textLength = text.length,
12607           exp,
12608           concat = [],
12609           expressionPositions = [];
12610
12611       while (index < textLength) {
12612         if (((startIndex = text.indexOf(startSymbol, index)) !== -1) &&
12613              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) !== -1)) {
12614           if (index !== startIndex) {
12615             concat.push(unescapeText(text.substring(index, startIndex)));
12616           }
12617           exp = text.substring(startIndex + startSymbolLength, endIndex);
12618           expressions.push(exp);
12619           parseFns.push($parse(exp, parseStringifyInterceptor));
12620           index = endIndex + endSymbolLength;
12621           expressionPositions.push(concat.length);
12622           concat.push('');
12623         } else {
12624           // we did not find an interpolation, so we have to add the remainder to the separators array
12625           if (index !== textLength) {
12626             concat.push(unescapeText(text.substring(index)));
12627           }
12628           break;
12629         }
12630       }
12631
12632       // Concatenating expressions makes it hard to reason about whether some combination of
12633       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
12634       // single expression be used for iframe[src], object[src], etc., we ensure that the value
12635       // that's used is assigned or constructed by some JS code somewhere that is more testable or
12636       // make it obvious that you bound the value to some user controlled value.  This helps reduce
12637       // the load when auditing for XSS issues.
12638       if (trustedContext && concat.length > 1) {
12639           $interpolateMinErr.throwNoconcat(text);
12640       }
12641
12642       if (!mustHaveExpression || expressions.length) {
12643         var compute = function(values) {
12644           for (var i = 0, ii = expressions.length; i < ii; i++) {
12645             if (allOrNothing && isUndefined(values[i])) return;
12646             concat[expressionPositions[i]] = values[i];
12647           }
12648           return concat.join('');
12649         };
12650
12651         var getValue = function(value) {
12652           return trustedContext ?
12653             $sce.getTrusted(trustedContext, value) :
12654             $sce.valueOf(value);
12655         };
12656
12657         return extend(function interpolationFn(context) {
12658             var i = 0;
12659             var ii = expressions.length;
12660             var values = new Array(ii);
12661
12662             try {
12663               for (; i < ii; i++) {
12664                 values[i] = parseFns[i](context);
12665               }
12666
12667               return compute(values);
12668             } catch (err) {
12669               $exceptionHandler($interpolateMinErr.interr(text, err));
12670             }
12671
12672           }, {
12673           // all of these properties are undocumented for now
12674           exp: text, //just for compatibility with regular watchers created via $watch
12675           expressions: expressions,
12676           $$watchDelegate: function(scope, listener) {
12677             var lastValue;
12678             return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) {
12679               var currValue = compute(values);
12680               if (isFunction(listener)) {
12681                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
12682               }
12683               lastValue = currValue;
12684             });
12685           }
12686         });
12687       }
12688
12689       function parseStringifyInterceptor(value) {
12690         try {
12691           value = getValue(value);
12692           return allOrNothing && !isDefined(value) ? value : stringify(value);
12693         } catch (err) {
12694           $exceptionHandler($interpolateMinErr.interr(text, err));
12695         }
12696       }
12697     }
12698
12699
12700     /**
12701      * @ngdoc method
12702      * @name $interpolate#startSymbol
12703      * @description
12704      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
12705      *
12706      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
12707      * the symbol.
12708      *
12709      * @returns {string} start symbol.
12710      */
12711     $interpolate.startSymbol = function() {
12712       return startSymbol;
12713     };
12714
12715
12716     /**
12717      * @ngdoc method
12718      * @name $interpolate#endSymbol
12719      * @description
12720      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
12721      *
12722      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
12723      * the symbol.
12724      *
12725      * @returns {string} end symbol.
12726      */
12727     $interpolate.endSymbol = function() {
12728       return endSymbol;
12729     };
12730
12731     return $interpolate;
12732   }];
12733 }
12734
12735 /** @this */
12736 function $IntervalProvider() {
12737   this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
12738        function($rootScope,   $window,   $q,   $$q,   $browser) {
12739     var intervals = {};
12740
12741
12742      /**
12743       * @ngdoc service
12744       * @name $interval
12745       *
12746       * @description
12747       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
12748       * milliseconds.
12749       *
12750       * The return value of registering an interval function is a promise. This promise will be
12751       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
12752       * run indefinitely if `count` is not defined. The value of the notification will be the
12753       * number of iterations that have run.
12754       * To cancel an interval, call `$interval.cancel(promise)`.
12755       *
12756       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
12757       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
12758       * time.
12759       *
12760       * <div class="alert alert-warning">
12761       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
12762       * with them.  In particular they are not automatically destroyed when a controller's scope or a
12763       * directive's element are destroyed.
12764       * You should take this into consideration and make sure to always cancel the interval at the
12765       * appropriate moment.  See the example below for more details on how and when to do this.
12766       * </div>
12767       *
12768       * @param {function()} fn A function that should be called repeatedly. If no additional arguments
12769       *   are passed (see below), the function is called with the current iteration count.
12770       * @param {number} delay Number of milliseconds between each function call.
12771       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
12772       *   indefinitely.
12773       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
12774       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
12775       * @param {...*=} Pass additional parameters to the executed function.
12776       * @returns {promise} A promise which will be notified on each iteration.
12777       *
12778       * @example
12779       * <example module="intervalExample" name="interval-service">
12780       * <file name="index.html">
12781       *   <script>
12782       *     angular.module('intervalExample', [])
12783       *       .controller('ExampleController', ['$scope', '$interval',
12784       *         function($scope, $interval) {
12785       *           $scope.format = 'M/d/yy h:mm:ss a';
12786       *           $scope.blood_1 = 100;
12787       *           $scope.blood_2 = 120;
12788       *
12789       *           var stop;
12790       *           $scope.fight = function() {
12791       *             // Don't start a new fight if we are already fighting
12792       *             if ( angular.isDefined(stop) ) return;
12793       *
12794       *             stop = $interval(function() {
12795       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
12796       *                 $scope.blood_1 = $scope.blood_1 - 3;
12797       *                 $scope.blood_2 = $scope.blood_2 - 4;
12798       *               } else {
12799       *                 $scope.stopFight();
12800       *               }
12801       *             }, 100);
12802       *           };
12803       *
12804       *           $scope.stopFight = function() {
12805       *             if (angular.isDefined(stop)) {
12806       *               $interval.cancel(stop);
12807       *               stop = undefined;
12808       *             }
12809       *           };
12810       *
12811       *           $scope.resetFight = function() {
12812       *             $scope.blood_1 = 100;
12813       *             $scope.blood_2 = 120;
12814       *           };
12815       *
12816       *           $scope.$on('$destroy', function() {
12817       *             // Make sure that the interval is destroyed too
12818       *             $scope.stopFight();
12819       *           });
12820       *         }])
12821       *       // Register the 'myCurrentTime' directive factory method.
12822       *       // We inject $interval and dateFilter service since the factory method is DI.
12823       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
12824       *         function($interval, dateFilter) {
12825       *           // return the directive link function. (compile function not needed)
12826       *           return function(scope, element, attrs) {
12827       *             var format,  // date format
12828       *                 stopTime; // so that we can cancel the time updates
12829       *
12830       *             // used to update the UI
12831       *             function updateTime() {
12832       *               element.text(dateFilter(new Date(), format));
12833       *             }
12834       *
12835       *             // watch the expression, and update the UI on change.
12836       *             scope.$watch(attrs.myCurrentTime, function(value) {
12837       *               format = value;
12838       *               updateTime();
12839       *             });
12840       *
12841       *             stopTime = $interval(updateTime, 1000);
12842       *
12843       *             // listen on DOM destroy (removal) event, and cancel the next UI update
12844       *             // to prevent updating time after the DOM element was removed.
12845       *             element.on('$destroy', function() {
12846       *               $interval.cancel(stopTime);
12847       *             });
12848       *           }
12849       *         }]);
12850       *   </script>
12851       *
12852       *   <div>
12853       *     <div ng-controller="ExampleController">
12854       *       <label>Date format: <input ng-model="format"></label> <hr/>
12855       *       Current time is: <span my-current-time="format"></span>
12856       *       <hr/>
12857       *       Blood 1 : <font color='red'>{{blood_1}}</font>
12858       *       Blood 2 : <font color='red'>{{blood_2}}</font>
12859       *       <button type="button" data-ng-click="fight()">Fight</button>
12860       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
12861       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
12862       *     </div>
12863       *   </div>
12864       *
12865       * </file>
12866       * </example>
12867       */
12868     function interval(fn, delay, count, invokeApply) {
12869       var hasParams = arguments.length > 4,
12870           args = hasParams ? sliceArgs(arguments, 4) : [],
12871           setInterval = $window.setInterval,
12872           clearInterval = $window.clearInterval,
12873           iteration = 0,
12874           skipApply = (isDefined(invokeApply) && !invokeApply),
12875           deferred = (skipApply ? $$q : $q).defer(),
12876           promise = deferred.promise;
12877
12878       count = isDefined(count) ? count : 0;
12879
12880       promise.$$intervalId = setInterval(function tick() {
12881         if (skipApply) {
12882           $browser.defer(callback);
12883         } else {
12884           $rootScope.$evalAsync(callback);
12885         }
12886         deferred.notify(iteration++);
12887
12888         if (count > 0 && iteration >= count) {
12889           deferred.resolve(iteration);
12890           clearInterval(promise.$$intervalId);
12891           delete intervals[promise.$$intervalId];
12892         }
12893
12894         if (!skipApply) $rootScope.$apply();
12895
12896       }, delay);
12897
12898       intervals[promise.$$intervalId] = deferred;
12899
12900       return promise;
12901
12902       function callback() {
12903         if (!hasParams) {
12904           fn(iteration);
12905         } else {
12906           fn.apply(null, args);
12907         }
12908       }
12909     }
12910
12911
12912      /**
12913       * @ngdoc method
12914       * @name $interval#cancel
12915       *
12916       * @description
12917       * Cancels a task associated with the `promise`.
12918       *
12919       * @param {Promise=} promise returned by the `$interval` function.
12920       * @returns {boolean} Returns `true` if the task was successfully canceled.
12921       */
12922     interval.cancel = function(promise) {
12923       if (promise && promise.$$intervalId in intervals) {
12924         intervals[promise.$$intervalId].reject('canceled');
12925         $window.clearInterval(promise.$$intervalId);
12926         delete intervals[promise.$$intervalId];
12927         return true;
12928       }
12929       return false;
12930     };
12931
12932     return interval;
12933   }];
12934 }
12935
12936 /**
12937  * @ngdoc service
12938  * @name $jsonpCallbacks
12939  * @requires $window
12940  * @description
12941  * This service handles the lifecycle of callbacks to handle JSONP requests.
12942  * Override this service if you wish to customise where the callbacks are stored and
12943  * how they vary compared to the requested url.
12944  */
12945 var $jsonpCallbacksProvider = /** @this */ function() {
12946   this.$get = ['$window', function($window) {
12947     var callbacks = $window.angular.callbacks;
12948     var callbackMap = {};
12949
12950     function createCallback(callbackId) {
12951       var callback = function(data) {
12952         callback.data = data;
12953         callback.called = true;
12954       };
12955       callback.id = callbackId;
12956       return callback;
12957     }
12958
12959     return {
12960       /**
12961        * @ngdoc method
12962        * @name $jsonpCallbacks#createCallback
12963        * @param {string} url the url of the JSONP request
12964        * @returns {string} the callback path to send to the server as part of the JSONP request
12965        * @description
12966        * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback
12967        * to pass to the server, which will be used to call the callback with its payload in the JSONP response.
12968        */
12969       createCallback: function(url) {
12970         var callbackId = '_' + (callbacks.$$counter++).toString(36);
12971         var callbackPath = 'angular.callbacks.' + callbackId;
12972         var callback = createCallback(callbackId);
12973         callbackMap[callbackPath] = callbacks[callbackId] = callback;
12974         return callbackPath;
12975       },
12976       /**
12977        * @ngdoc method
12978        * @name $jsonpCallbacks#wasCalled
12979        * @param {string} callbackPath the path to the callback that was sent in the JSONP request
12980        * @returns {boolean} whether the callback has been called, as a result of the JSONP response
12981        * @description
12982        * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the
12983        * callback that was passed in the request.
12984        */
12985       wasCalled: function(callbackPath) {
12986         return callbackMap[callbackPath].called;
12987       },
12988       /**
12989        * @ngdoc method
12990        * @name $jsonpCallbacks#getResponse
12991        * @param {string} callbackPath the path to the callback that was sent in the JSONP request
12992        * @returns {*} the data received from the response via the registered callback
12993        * @description
12994        * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback
12995        * in the JSONP response.
12996        */
12997       getResponse: function(callbackPath) {
12998         return callbackMap[callbackPath].data;
12999       },
13000       /**
13001        * @ngdoc method
13002        * @name $jsonpCallbacks#removeCallback
13003        * @param {string} callbackPath the path to the callback that was sent in the JSONP request
13004        * @description
13005        * {@link $httpBackend} calls this method to remove the callback after the JSONP request has
13006        * completed or timed-out.
13007        */
13008       removeCallback: function(callbackPath) {
13009         var callback = callbackMap[callbackPath];
13010         delete callbacks[callback.id];
13011         delete callbackMap[callbackPath];
13012       }
13013     };
13014   }];
13015 };
13016
13017 /**
13018  * @ngdoc service
13019  * @name $locale
13020  *
13021  * @description
13022  * $locale service provides localization rules for various Angular components. As of right now the
13023  * only public api is:
13024  *
13025  * * `id` â€“ `{string}` â€“ locale id formatted as `languageId-countryId` (e.g. `en-us`)
13026  */
13027
13028 var PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/,
13029     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
13030 var $locationMinErr = minErr('$location');
13031
13032
13033 /**
13034  * Encode path using encodeUriSegment, ignoring forward slashes
13035  *
13036  * @param {string} path Path to encode
13037  * @returns {string}
13038  */
13039 function encodePath(path) {
13040   var segments = path.split('/'),
13041       i = segments.length;
13042
13043   while (i--) {
13044     segments[i] = encodeUriSegment(segments[i]);
13045   }
13046
13047   return segments.join('/');
13048 }
13049
13050 function parseAbsoluteUrl(absoluteUrl, locationObj) {
13051   var parsedUrl = urlResolve(absoluteUrl);
13052
13053   locationObj.$$protocol = parsedUrl.protocol;
13054   locationObj.$$host = parsedUrl.hostname;
13055   locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
13056 }
13057
13058 var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
13059 function parseAppUrl(url, locationObj) {
13060
13061   if (DOUBLE_SLASH_REGEX.test(url)) {
13062     throw $locationMinErr('badpath', 'Invalid url "{0}".', url);
13063   }
13064
13065   var prefixed = (url.charAt(0) !== '/');
13066   if (prefixed) {
13067     url = '/' + url;
13068   }
13069   var match = urlResolve(url);
13070   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
13071       match.pathname.substring(1) : match.pathname);
13072   locationObj.$$search = parseKeyValue(match.search);
13073   locationObj.$$hash = decodeURIComponent(match.hash);
13074
13075   // make sure path starts with '/';
13076   if (locationObj.$$path && locationObj.$$path.charAt(0) !== '/') {
13077     locationObj.$$path = '/' + locationObj.$$path;
13078   }
13079 }
13080
13081 function startsWith(str, search) {
13082   return str.slice(0, search.length) === search;
13083 }
13084
13085 /**
13086  *
13087  * @param {string} base
13088  * @param {string} url
13089  * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
13090  *                   the expected string.
13091  */
13092 function stripBaseUrl(base, url) {
13093   if (startsWith(url, base)) {
13094     return url.substr(base.length);
13095   }
13096 }
13097
13098
13099 function stripHash(url) {
13100   var index = url.indexOf('#');
13101   return index === -1 ? url : url.substr(0, index);
13102 }
13103
13104 function trimEmptyHash(url) {
13105   return url.replace(/(#.+)|#$/, '$1');
13106 }
13107
13108
13109 function stripFile(url) {
13110   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
13111 }
13112
13113 /* return the server only (scheme://host:port) */
13114 function serverBase(url) {
13115   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
13116 }
13117
13118
13119 /**
13120  * LocationHtml5Url represents a URL
13121  * This object is exposed as $location service when HTML5 mode is enabled and supported
13122  *
13123  * @constructor
13124  * @param {string} appBase application base URL
13125  * @param {string} appBaseNoFile application base URL stripped of any filename
13126  * @param {string} basePrefix URL path prefix
13127  */
13128 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
13129   this.$$html5 = true;
13130   basePrefix = basePrefix || '';
13131   parseAbsoluteUrl(appBase, this);
13132
13133
13134   /**
13135    * Parse given HTML5 (regular) URL string into properties
13136    * @param {string} url HTML5 URL
13137    * @private
13138    */
13139   this.$$parse = function(url) {
13140     var pathUrl = stripBaseUrl(appBaseNoFile, url);
13141     if (!isString(pathUrl)) {
13142       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
13143           appBaseNoFile);
13144     }
13145
13146     parseAppUrl(pathUrl, this);
13147
13148     if (!this.$$path) {
13149       this.$$path = '/';
13150     }
13151
13152     this.$$compose();
13153   };
13154
13155   /**
13156    * Compose url and update `absUrl` property
13157    * @private
13158    */
13159   this.$$compose = function() {
13160     var search = toKeyValue(this.$$search),
13161         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
13162
13163     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
13164     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
13165   };
13166
13167   this.$$parseLinkUrl = function(url, relHref) {
13168     if (relHref && relHref[0] === '#') {
13169       // special case for links to hash fragments:
13170       // keep the old url and only replace the hash fragment
13171       this.hash(relHref.slice(1));
13172       return true;
13173     }
13174     var appUrl, prevAppUrl;
13175     var rewrittenUrl;
13176
13177
13178     if (isDefined(appUrl = stripBaseUrl(appBase, url))) {
13179       prevAppUrl = appUrl;
13180       if (basePrefix && isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) {
13181         rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl);
13182       } else {
13183         rewrittenUrl = appBase + prevAppUrl;
13184       }
13185     } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) {
13186       rewrittenUrl = appBaseNoFile + appUrl;
13187     } else if (appBaseNoFile === url + '/') {
13188       rewrittenUrl = appBaseNoFile;
13189     }
13190     if (rewrittenUrl) {
13191       this.$$parse(rewrittenUrl);
13192     }
13193     return !!rewrittenUrl;
13194   };
13195 }
13196
13197
13198 /**
13199  * LocationHashbangUrl represents URL
13200  * This object is exposed as $location service when developer doesn't opt into html5 mode.
13201  * It also serves as the base class for html5 mode fallback on legacy browsers.
13202  *
13203  * @constructor
13204  * @param {string} appBase application base URL
13205  * @param {string} appBaseNoFile application base URL stripped of any filename
13206  * @param {string} hashPrefix hashbang prefix
13207  */
13208 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
13209
13210   parseAbsoluteUrl(appBase, this);
13211
13212
13213   /**
13214    * Parse given hashbang URL into properties
13215    * @param {string} url Hashbang URL
13216    * @private
13217    */
13218   this.$$parse = function(url) {
13219     var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url);
13220     var withoutHashUrl;
13221
13222     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
13223
13224       // The rest of the URL starts with a hash so we have
13225       // got either a hashbang path or a plain hash fragment
13226       withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);
13227       if (isUndefined(withoutHashUrl)) {
13228         // There was no hashbang prefix so we just have a hash fragment
13229         withoutHashUrl = withoutBaseUrl;
13230       }
13231
13232     } else {
13233       // There was no hashbang path nor hash fragment:
13234       // If we are in HTML5 mode we use what is left as the path;
13235       // Otherwise we ignore what is left
13236       if (this.$$html5) {
13237         withoutHashUrl = withoutBaseUrl;
13238       } else {
13239         withoutHashUrl = '';
13240         if (isUndefined(withoutBaseUrl)) {
13241           appBase = url;
13242           this.replace();
13243         }
13244       }
13245     }
13246
13247     parseAppUrl(withoutHashUrl, this);
13248
13249     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
13250
13251     this.$$compose();
13252
13253     /*
13254      * In Windows, on an anchor node on documents loaded from
13255      * the filesystem, the browser will return a pathname
13256      * prefixed with the drive name ('/C:/path') when a
13257      * pathname without a drive is set:
13258      *  * a.setAttribute('href', '/foo')
13259      *   * a.pathname === '/C:/foo' //true
13260      *
13261      * Inside of Angular, we're always using pathnames that
13262      * do not include drive names for routing.
13263      */
13264     function removeWindowsDriveName(path, url, base) {
13265       /*
13266       Matches paths for file protocol on windows,
13267       such as /C:/foo/bar, and captures only /foo/bar.
13268       */
13269       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
13270
13271       var firstPathSegmentMatch;
13272
13273       //Get the relative path from the input URL.
13274       if (startsWith(url, base)) {
13275         url = url.replace(base, '');
13276       }
13277
13278       // The input URL intentionally contains a first path segment that ends with a colon.
13279       if (windowsFilePathExp.exec(url)) {
13280         return path;
13281       }
13282
13283       firstPathSegmentMatch = windowsFilePathExp.exec(path);
13284       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
13285     }
13286   };
13287
13288   /**
13289    * Compose hashbang URL and update `absUrl` property
13290    * @private
13291    */
13292   this.$$compose = function() {
13293     var search = toKeyValue(this.$$search),
13294         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
13295
13296     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
13297     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
13298   };
13299
13300   this.$$parseLinkUrl = function(url, relHref) {
13301     if (stripHash(appBase) === stripHash(url)) {
13302       this.$$parse(url);
13303       return true;
13304     }
13305     return false;
13306   };
13307 }
13308
13309
13310 /**
13311  * LocationHashbangUrl represents URL
13312  * This object is exposed as $location service when html5 history api is enabled but the browser
13313  * does not support it.
13314  *
13315  * @constructor
13316  * @param {string} appBase application base URL
13317  * @param {string} appBaseNoFile application base URL stripped of any filename
13318  * @param {string} hashPrefix hashbang prefix
13319  */
13320 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
13321   this.$$html5 = true;
13322   LocationHashbangUrl.apply(this, arguments);
13323
13324   this.$$parseLinkUrl = function(url, relHref) {
13325     if (relHref && relHref[0] === '#') {
13326       // special case for links to hash fragments:
13327       // keep the old url and only replace the hash fragment
13328       this.hash(relHref.slice(1));
13329       return true;
13330     }
13331
13332     var rewrittenUrl;
13333     var appUrl;
13334
13335     if (appBase === stripHash(url)) {
13336       rewrittenUrl = url;
13337     } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {
13338       rewrittenUrl = appBase + hashPrefix + appUrl;
13339     } else if (appBaseNoFile === url + '/') {
13340       rewrittenUrl = appBaseNoFile;
13341     }
13342     if (rewrittenUrl) {
13343       this.$$parse(rewrittenUrl);
13344     }
13345     return !!rewrittenUrl;
13346   };
13347
13348   this.$$compose = function() {
13349     var search = toKeyValue(this.$$search),
13350         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
13351
13352     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
13353     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
13354     this.$$absUrl = appBase + hashPrefix + this.$$url;
13355   };
13356
13357 }
13358
13359
13360 var locationPrototype = {
13361
13362   /**
13363    * Ensure absolute URL is initialized.
13364    * @private
13365    */
13366   $$absUrl:'',
13367
13368   /**
13369    * Are we in html5 mode?
13370    * @private
13371    */
13372   $$html5: false,
13373
13374   /**
13375    * Has any change been replacing?
13376    * @private
13377    */
13378   $$replace: false,
13379
13380   /**
13381    * @ngdoc method
13382    * @name $location#absUrl
13383    *
13384    * @description
13385    * This method is getter only.
13386    *
13387    * Return full URL representation with all segments encoded according to rules specified in
13388    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
13389    *
13390    *
13391    * ```js
13392    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13393    * var absUrl = $location.absUrl();
13394    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
13395    * ```
13396    *
13397    * @return {string} full URL
13398    */
13399   absUrl: locationGetter('$$absUrl'),
13400
13401   /**
13402    * @ngdoc method
13403    * @name $location#url
13404    *
13405    * @description
13406    * This method is getter / setter.
13407    *
13408    * Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
13409    *
13410    * Change path, search and hash, when called with parameter and return `$location`.
13411    *
13412    *
13413    * ```js
13414    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13415    * var url = $location.url();
13416    * // => "/some/path?foo=bar&baz=xoxo"
13417    * ```
13418    *
13419    * @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`)
13420    * @return {string} url
13421    */
13422   url: function(url) {
13423     if (isUndefined(url)) {
13424       return this.$$url;
13425     }
13426
13427     var match = PATH_MATCH.exec(url);
13428     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
13429     if (match[2] || match[1] || url === '') this.search(match[3] || '');
13430     this.hash(match[5] || '');
13431
13432     return this;
13433   },
13434
13435   /**
13436    * @ngdoc method
13437    * @name $location#protocol
13438    *
13439    * @description
13440    * This method is getter only.
13441    *
13442    * Return protocol of current URL.
13443    *
13444    *
13445    * ```js
13446    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13447    * var protocol = $location.protocol();
13448    * // => "http"
13449    * ```
13450    *
13451    * @return {string} protocol of current URL
13452    */
13453   protocol: locationGetter('$$protocol'),
13454
13455   /**
13456    * @ngdoc method
13457    * @name $location#host
13458    *
13459    * @description
13460    * This method is getter only.
13461    *
13462    * Return host of current URL.
13463    *
13464    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
13465    *
13466    *
13467    * ```js
13468    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13469    * var host = $location.host();
13470    * // => "example.com"
13471    *
13472    * // given URL http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
13473    * host = $location.host();
13474    * // => "example.com"
13475    * host = location.host;
13476    * // => "example.com:8080"
13477    * ```
13478    *
13479    * @return {string} host of current URL.
13480    */
13481   host: locationGetter('$$host'),
13482
13483   /**
13484    * @ngdoc method
13485    * @name $location#port
13486    *
13487    * @description
13488    * This method is getter only.
13489    *
13490    * Return port of current URL.
13491    *
13492    *
13493    * ```js
13494    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13495    * var port = $location.port();
13496    * // => 80
13497    * ```
13498    *
13499    * @return {Number} port
13500    */
13501   port: locationGetter('$$port'),
13502
13503   /**
13504    * @ngdoc method
13505    * @name $location#path
13506    *
13507    * @description
13508    * This method is getter / setter.
13509    *
13510    * Return path of current URL when called without any parameter.
13511    *
13512    * Change path when called with parameter and return `$location`.
13513    *
13514    * Note: Path should always begin with forward slash (/), this method will add the forward slash
13515    * if it is missing.
13516    *
13517    *
13518    * ```js
13519    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13520    * var path = $location.path();
13521    * // => "/some/path"
13522    * ```
13523    *
13524    * @param {(string|number)=} path New path
13525    * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
13526    */
13527   path: locationGetterSetter('$$path', function(path) {
13528     path = path !== null ? path.toString() : '';
13529     return path.charAt(0) === '/' ? path : '/' + path;
13530   }),
13531
13532   /**
13533    * @ngdoc method
13534    * @name $location#search
13535    *
13536    * @description
13537    * This method is getter / setter.
13538    *
13539    * Return search part (as object) of current URL when called without any parameter.
13540    *
13541    * Change search part when called with parameter and return `$location`.
13542    *
13543    *
13544    * ```js
13545    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
13546    * var searchObject = $location.search();
13547    * // => {foo: 'bar', baz: 'xoxo'}
13548    *
13549    * // set foo to 'yipee'
13550    * $location.search('foo', 'yipee');
13551    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
13552    * ```
13553    *
13554    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
13555    * hash object.
13556    *
13557    * When called with a single argument the method acts as a setter, setting the `search` component
13558    * of `$location` to the specified value.
13559    *
13560    * If the argument is a hash object containing an array of values, these values will be encoded
13561    * as duplicate search parameters in the URL.
13562    *
13563    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
13564    * will override only a single search property.
13565    *
13566    * If `paramValue` is an array, it will override the property of the `search` component of
13567    * `$location` specified via the first argument.
13568    *
13569    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
13570    *
13571    * If `paramValue` is `true`, the property specified via the first argument will be added with no
13572    * value nor trailing equal sign.
13573    *
13574    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
13575    * one or more arguments returns `$location` object itself.
13576    */
13577   search: function(search, paramValue) {
13578     switch (arguments.length) {
13579       case 0:
13580         return this.$$search;
13581       case 1:
13582         if (isString(search) || isNumber(search)) {
13583           search = search.toString();
13584           this.$$search = parseKeyValue(search);
13585         } else if (isObject(search)) {
13586           search = copy(search, {});
13587           // remove object undefined or null properties
13588           forEach(search, function(value, key) {
13589             if (value == null) delete search[key];
13590           });
13591
13592           this.$$search = search;
13593         } else {
13594           throw $locationMinErr('isrcharg',
13595               'The first argument of the `$location#search()` call must be a string or an object.');
13596         }
13597         break;
13598       default:
13599         if (isUndefined(paramValue) || paramValue === null) {
13600           delete this.$$search[search];
13601         } else {
13602           this.$$search[search] = paramValue;
13603         }
13604     }
13605
13606     this.$$compose();
13607     return this;
13608   },
13609
13610   /**
13611    * @ngdoc method
13612    * @name $location#hash
13613    *
13614    * @description
13615    * This method is getter / setter.
13616    *
13617    * Returns the hash fragment when called without any parameters.
13618    *
13619    * Changes the hash fragment when called with a parameter and returns `$location`.
13620    *
13621    *
13622    * ```js
13623    * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
13624    * var hash = $location.hash();
13625    * // => "hashValue"
13626    * ```
13627    *
13628    * @param {(string|number)=} hash New hash fragment
13629    * @return {string} hash
13630    */
13631   hash: locationGetterSetter('$$hash', function(hash) {
13632     return hash !== null ? hash.toString() : '';
13633   }),
13634
13635   /**
13636    * @ngdoc method
13637    * @name $location#replace
13638    *
13639    * @description
13640    * If called, all changes to $location during the current `$digest` will replace the current history
13641    * record, instead of adding a new one.
13642    */
13643   replace: function() {
13644     this.$$replace = true;
13645     return this;
13646   }
13647 };
13648
13649 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
13650   Location.prototype = Object.create(locationPrototype);
13651
13652   /**
13653    * @ngdoc method
13654    * @name $location#state
13655    *
13656    * @description
13657    * This method is getter / setter.
13658    *
13659    * Return the history state object when called without any parameter.
13660    *
13661    * Change the history state object when called with one parameter and return `$location`.
13662    * The state object is later passed to `pushState` or `replaceState`.
13663    *
13664    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
13665    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
13666    * older browsers (like IE9 or Android < 4.0), don't use this method.
13667    *
13668    * @param {object=} state State object for pushState or replaceState
13669    * @return {object} state
13670    */
13671   Location.prototype.state = function(state) {
13672     if (!arguments.length) {
13673       return this.$$state;
13674     }
13675
13676     if (Location !== LocationHtml5Url || !this.$$html5) {
13677       throw $locationMinErr('nostate', 'History API state support is available only ' +
13678         'in HTML5 mode and only in browsers supporting HTML5 History API');
13679     }
13680     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
13681     // but we're changing the $$state reference to $browser.state() during the $digest
13682     // so the modification window is narrow.
13683     this.$$state = isUndefined(state) ? null : state;
13684
13685     return this;
13686   };
13687 });
13688
13689
13690 function locationGetter(property) {
13691   return /** @this */ function() {
13692     return this[property];
13693   };
13694 }
13695
13696
13697 function locationGetterSetter(property, preprocess) {
13698   return /** @this */ function(value) {
13699     if (isUndefined(value)) {
13700       return this[property];
13701     }
13702
13703     this[property] = preprocess(value);
13704     this.$$compose();
13705
13706     return this;
13707   };
13708 }
13709
13710
13711 /**
13712  * @ngdoc service
13713  * @name $location
13714  *
13715  * @requires $rootElement
13716  *
13717  * @description
13718  * The $location service parses the URL in the browser address bar (based on the
13719  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
13720  * available to your application. Changes to the URL in the address bar are reflected into
13721  * $location service and changes to $location are reflected into the browser address bar.
13722  *
13723  * **The $location service:**
13724  *
13725  * - Exposes the current URL in the browser address bar, so you can
13726  *   - Watch and observe the URL.
13727  *   - Change the URL.
13728  * - Synchronizes the URL with the browser when the user
13729  *   - Changes the address bar.
13730  *   - Clicks the back or forward button (or clicks a History link).
13731  *   - Clicks on a link.
13732  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
13733  *
13734  * For more information see {@link guide/$location Developer Guide: Using $location}
13735  */
13736
13737 /**
13738  * @ngdoc provider
13739  * @name $locationProvider
13740  * @this
13741  *
13742  * @description
13743  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
13744  */
13745 function $LocationProvider() {
13746   var hashPrefix = '',
13747       html5Mode = {
13748         enabled: false,
13749         requireBase: true,
13750         rewriteLinks: true
13751       };
13752
13753   /**
13754    * @ngdoc method
13755    * @name $locationProvider#hashPrefix
13756    * @description
13757    * The default value for the prefix is `''`.
13758    * @param {string=} prefix Prefix for hash part (containing path and search)
13759    * @returns {*} current value if used as getter or itself (chaining) if used as setter
13760    */
13761   this.hashPrefix = function(prefix) {
13762     if (isDefined(prefix)) {
13763       hashPrefix = prefix;
13764       return this;
13765     } else {
13766       return hashPrefix;
13767     }
13768   };
13769
13770   /**
13771    * @ngdoc method
13772    * @name $locationProvider#html5Mode
13773    * @description
13774    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
13775    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
13776    *   properties:
13777    *   - **enabled** â€“ `{boolean}` â€“ (default: false) If true, will rely on `history.pushState` to
13778    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
13779    *     support `pushState`.
13780    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
13781    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
13782    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
13783    *     See the {@link guide/$location $location guide for more information}
13784    *   - **rewriteLinks** - `{boolean|string}` - (default: `true`) When html5Mode is enabled,
13785    *     enables/disables URL rewriting for relative links. If set to a string, URL rewriting will
13786    *     only happen on links with an attribute that matches the given string. For example, if set
13787    *     to `'internal-link'`, then the URL will only be rewritten for `<a internal-link>` links.
13788    *     Note that [attribute name normalization](guide/directive#normalization) does not apply
13789    *     here, so `'internalLink'` will **not** match `'internal-link'`.
13790    *
13791    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
13792    */
13793   this.html5Mode = function(mode) {
13794     if (isBoolean(mode)) {
13795       html5Mode.enabled = mode;
13796       return this;
13797     } else if (isObject(mode)) {
13798
13799       if (isBoolean(mode.enabled)) {
13800         html5Mode.enabled = mode.enabled;
13801       }
13802
13803       if (isBoolean(mode.requireBase)) {
13804         html5Mode.requireBase = mode.requireBase;
13805       }
13806
13807       if (isBoolean(mode.rewriteLinks) || isString(mode.rewriteLinks)) {
13808         html5Mode.rewriteLinks = mode.rewriteLinks;
13809       }
13810
13811       return this;
13812     } else {
13813       return html5Mode;
13814     }
13815   };
13816
13817   /**
13818    * @ngdoc event
13819    * @name $location#$locationChangeStart
13820    * @eventType broadcast on root scope
13821    * @description
13822    * Broadcasted before a URL will change.
13823    *
13824    * This change can be prevented by calling
13825    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
13826    * details about event object. Upon successful change
13827    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
13828    *
13829    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
13830    * the browser supports the HTML5 History API.
13831    *
13832    * @param {Object} angularEvent Synthetic event object.
13833    * @param {string} newUrl New URL
13834    * @param {string=} oldUrl URL that was before it was changed.
13835    * @param {string=} newState New history state object
13836    * @param {string=} oldState History state object that was before it was changed.
13837    */
13838
13839   /**
13840    * @ngdoc event
13841    * @name $location#$locationChangeSuccess
13842    * @eventType broadcast on root scope
13843    * @description
13844    * Broadcasted after a URL was changed.
13845    *
13846    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
13847    * the browser supports the HTML5 History API.
13848    *
13849    * @param {Object} angularEvent Synthetic event object.
13850    * @param {string} newUrl New URL
13851    * @param {string=} oldUrl URL that was before it was changed.
13852    * @param {string=} newState New history state object
13853    * @param {string=} oldState History state object that was before it was changed.
13854    */
13855
13856   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
13857       function($rootScope, $browser, $sniffer, $rootElement, $window) {
13858     var $location,
13859         LocationMode,
13860         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
13861         initialUrl = $browser.url(),
13862         appBase;
13863
13864     if (html5Mode.enabled) {
13865       if (!baseHref && html5Mode.requireBase) {
13866         throw $locationMinErr('nobase',
13867           '$location in HTML5 mode requires a <base> tag to be present!');
13868       }
13869       appBase = serverBase(initialUrl) + (baseHref || '/');
13870       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
13871     } else {
13872       appBase = stripHash(initialUrl);
13873       LocationMode = LocationHashbangUrl;
13874     }
13875     var appBaseNoFile = stripFile(appBase);
13876
13877     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
13878     $location.$$parseLinkUrl(initialUrl, initialUrl);
13879
13880     $location.$$state = $browser.state();
13881
13882     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
13883
13884     function setBrowserUrlWithFallback(url, replace, state) {
13885       var oldUrl = $location.url();
13886       var oldState = $location.$$state;
13887       try {
13888         $browser.url(url, replace, state);
13889
13890         // Make sure $location.state() returns referentially identical (not just deeply equal)
13891         // state object; this makes possible quick checking if the state changed in the digest
13892         // loop. Checking deep equality would be too expensive.
13893         $location.$$state = $browser.state();
13894       } catch (e) {
13895         // Restore old values if pushState fails
13896         $location.url(oldUrl);
13897         $location.$$state = oldState;
13898
13899         throw e;
13900       }
13901     }
13902
13903     $rootElement.on('click', function(event) {
13904       var rewriteLinks = html5Mode.rewriteLinks;
13905       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
13906       // currently we open nice url link and redirect then
13907
13908       if (!rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return;
13909
13910       var elm = jqLite(event.target);
13911
13912       // traverse the DOM up to find first A tag
13913       while (nodeName_(elm[0]) !== 'a') {
13914         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
13915         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
13916       }
13917
13918       if (isString(rewriteLinks) && isUndefined(elm.attr(rewriteLinks))) return;
13919
13920       var absHref = elm.prop('href');
13921       // get the actual href attribute - see
13922       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
13923       var relHref = elm.attr('href') || elm.attr('xlink:href');
13924
13925       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
13926         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
13927         // an animation.
13928         absHref = urlResolve(absHref.animVal).href;
13929       }
13930
13931       // Ignore when url is started with javascript: or mailto:
13932       if (IGNORE_URI_REGEXP.test(absHref)) return;
13933
13934       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
13935         if ($location.$$parseLinkUrl(absHref, relHref)) {
13936           // We do a preventDefault for all urls that are part of the angular application,
13937           // in html5mode and also without, so that we are able to abort navigation without
13938           // getting double entries in the location history.
13939           event.preventDefault();
13940           // update location manually
13941           if ($location.absUrl() !== $browser.url()) {
13942             $rootScope.$apply();
13943             // hack to work around FF6 bug 684208 when scenario runner clicks on links
13944             $window.angular['ff-684208-preventDefault'] = true;
13945           }
13946         }
13947       }
13948     });
13949
13950
13951     // rewrite hashbang url <> html5 url
13952     if (trimEmptyHash($location.absUrl()) !== trimEmptyHash(initialUrl)) {
13953       $browser.url($location.absUrl(), true);
13954     }
13955
13956     var initializing = true;
13957
13958     // update $location when $browser url changes
13959     $browser.onUrlChange(function(newUrl, newState) {
13960
13961       if (isUndefined(stripBaseUrl(appBaseNoFile, newUrl))) {
13962         // If we are navigating outside of the app then force a reload
13963         $window.location.href = newUrl;
13964         return;
13965       }
13966
13967       $rootScope.$evalAsync(function() {
13968         var oldUrl = $location.absUrl();
13969         var oldState = $location.$$state;
13970         var defaultPrevented;
13971         newUrl = trimEmptyHash(newUrl);
13972         $location.$$parse(newUrl);
13973         $location.$$state = newState;
13974
13975         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
13976             newState, oldState).defaultPrevented;
13977
13978         // if the location was changed by a `$locationChangeStart` handler then stop
13979         // processing this location change
13980         if ($location.absUrl() !== newUrl) return;
13981
13982         if (defaultPrevented) {
13983           $location.$$parse(oldUrl);
13984           $location.$$state = oldState;
13985           setBrowserUrlWithFallback(oldUrl, false, oldState);
13986         } else {
13987           initializing = false;
13988           afterLocationChange(oldUrl, oldState);
13989         }
13990       });
13991       if (!$rootScope.$$phase) $rootScope.$digest();
13992     });
13993
13994     // update browser
13995     $rootScope.$watch(function $locationWatch() {
13996       var oldUrl = trimEmptyHash($browser.url());
13997       var newUrl = trimEmptyHash($location.absUrl());
13998       var oldState = $browser.state();
13999       var currentReplace = $location.$$replace;
14000       var urlOrStateChanged = oldUrl !== newUrl ||
14001         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
14002
14003       if (initializing || urlOrStateChanged) {
14004         initializing = false;
14005
14006         $rootScope.$evalAsync(function() {
14007           var newUrl = $location.absUrl();
14008           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
14009               $location.$$state, oldState).defaultPrevented;
14010
14011           // if the location was changed by a `$locationChangeStart` handler then stop
14012           // processing this location change
14013           if ($location.absUrl() !== newUrl) return;
14014
14015           if (defaultPrevented) {
14016             $location.$$parse(oldUrl);
14017             $location.$$state = oldState;
14018           } else {
14019             if (urlOrStateChanged) {
14020               setBrowserUrlWithFallback(newUrl, currentReplace,
14021                                         oldState === $location.$$state ? null : $location.$$state);
14022             }
14023             afterLocationChange(oldUrl, oldState);
14024           }
14025         });
14026       }
14027
14028       $location.$$replace = false;
14029
14030       // we don't need to return anything because $evalAsync will make the digest loop dirty when
14031       // there is a change
14032     });
14033
14034     return $location;
14035
14036     function afterLocationChange(oldUrl, oldState) {
14037       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
14038         $location.$$state, oldState);
14039     }
14040 }];
14041 }
14042
14043 /**
14044  * @ngdoc service
14045  * @name $log
14046  * @requires $window
14047  *
14048  * @description
14049  * Simple service for logging. Default implementation safely writes the message
14050  * into the browser's console (if present).
14051  *
14052  * The main purpose of this service is to simplify debugging and troubleshooting.
14053  *
14054  * The default is to log `debug` messages. You can use
14055  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
14056  *
14057  * @example
14058    <example module="logExample" name="log-service">
14059      <file name="script.js">
14060        angular.module('logExample', [])
14061          .controller('LogController', ['$scope', '$log', function($scope, $log) {
14062            $scope.$log = $log;
14063            $scope.message = 'Hello World!';
14064          }]);
14065      </file>
14066      <file name="index.html">
14067        <div ng-controller="LogController">
14068          <p>Reload this page with open console, enter text and hit the log button...</p>
14069          <label>Message:
14070          <input type="text" ng-model="message" /></label>
14071          <button ng-click="$log.log(message)">log</button>
14072          <button ng-click="$log.warn(message)">warn</button>
14073          <button ng-click="$log.info(message)">info</button>
14074          <button ng-click="$log.error(message)">error</button>
14075          <button ng-click="$log.debug(message)">debug</button>
14076        </div>
14077      </file>
14078    </example>
14079  */
14080
14081 /**
14082  * @ngdoc provider
14083  * @name $logProvider
14084  * @this
14085  *
14086  * @description
14087  * Use the `$logProvider` to configure how the application logs messages
14088  */
14089 function $LogProvider() {
14090   var debug = true,
14091       self = this;
14092
14093   /**
14094    * @ngdoc method
14095    * @name $logProvider#debugEnabled
14096    * @description
14097    * @param {boolean=} flag enable or disable debug level messages
14098    * @returns {*} current value if used as getter or itself (chaining) if used as setter
14099    */
14100   this.debugEnabled = function(flag) {
14101     if (isDefined(flag)) {
14102       debug = flag;
14103     return this;
14104     } else {
14105       return debug;
14106     }
14107   };
14108
14109   this.$get = ['$window', function($window) {
14110     return {
14111       /**
14112        * @ngdoc method
14113        * @name $log#log
14114        *
14115        * @description
14116        * Write a log message
14117        */
14118       log: consoleLog('log'),
14119
14120       /**
14121        * @ngdoc method
14122        * @name $log#info
14123        *
14124        * @description
14125        * Write an information message
14126        */
14127       info: consoleLog('info'),
14128
14129       /**
14130        * @ngdoc method
14131        * @name $log#warn
14132        *
14133        * @description
14134        * Write a warning message
14135        */
14136       warn: consoleLog('warn'),
14137
14138       /**
14139        * @ngdoc method
14140        * @name $log#error
14141        *
14142        * @description
14143        * Write an error message
14144        */
14145       error: consoleLog('error'),
14146
14147       /**
14148        * @ngdoc method
14149        * @name $log#debug
14150        *
14151        * @description
14152        * Write a debug message
14153        */
14154       debug: (function() {
14155         var fn = consoleLog('debug');
14156
14157         return function() {
14158           if (debug) {
14159             fn.apply(self, arguments);
14160           }
14161         };
14162       })()
14163     };
14164
14165     function formatError(arg) {
14166       if (arg instanceof Error) {
14167         if (arg.stack) {
14168           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
14169               ? 'Error: ' + arg.message + '\n' + arg.stack
14170               : arg.stack;
14171         } else if (arg.sourceURL) {
14172           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
14173         }
14174       }
14175       return arg;
14176     }
14177
14178     function consoleLog(type) {
14179       var console = $window.console || {},
14180           logFn = console[type] || console.log || noop,
14181           hasApply = false;
14182
14183       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
14184       // The reason behind this is that console.log has type "object" in IE8...
14185       try {
14186         hasApply = !!logFn.apply;
14187       } catch (e) { /* empty */ }
14188
14189       if (hasApply) {
14190         return function() {
14191           var args = [];
14192           forEach(arguments, function(arg) {
14193             args.push(formatError(arg));
14194           });
14195           return logFn.apply(console, args);
14196         };
14197       }
14198
14199       // we are IE which either doesn't have window.console => this is noop and we do nothing,
14200       // or we are IE where console.log doesn't have apply so we log at least first 2 args
14201       return function(arg1, arg2) {
14202         logFn(arg1, arg2 == null ? '' : arg2);
14203       };
14204     }
14205   }];
14206 }
14207
14208 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
14209  *     Any commits to this file should be reviewed with security in mind.  *
14210  *   Changes to this file can potentially create security vulnerabilities. *
14211  *          An approval from 2 Core members with history of modifying      *
14212  *                         this file is required.                          *
14213  *                                                                         *
14214  *  Does the change somehow allow for arbitrary javascript to be executed? *
14215  *    Or allows for someone to change the prototype of built-in objects?   *
14216  *     Or gives undesired access to variables likes document or window?    *
14217  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14218
14219 var $parseMinErr = minErr('$parse');
14220
14221 var ARRAY_CTOR = [].constructor;
14222 var BOOLEAN_CTOR = (false).constructor;
14223 var FUNCTION_CTOR = Function.constructor;
14224 var NUMBER_CTOR = (0).constructor;
14225 var OBJECT_CTOR = {}.constructor;
14226 var STRING_CTOR = ''.constructor;
14227 var ARRAY_CTOR_PROTO = ARRAY_CTOR.prototype;
14228 var BOOLEAN_CTOR_PROTO = BOOLEAN_CTOR.prototype;
14229 var FUNCTION_CTOR_PROTO = FUNCTION_CTOR.prototype;
14230 var NUMBER_CTOR_PROTO = NUMBER_CTOR.prototype;
14231 var OBJECT_CTOR_PROTO = OBJECT_CTOR.prototype;
14232 var STRING_CTOR_PROTO = STRING_CTOR.prototype;
14233
14234 var CALL = FUNCTION_CTOR_PROTO.call;
14235 var APPLY = FUNCTION_CTOR_PROTO.apply;
14236 var BIND = FUNCTION_CTOR_PROTO.bind;
14237
14238 var objectValueOf = OBJECT_CTOR_PROTO.valueOf;
14239
14240 // Sandboxing Angular Expressions
14241 // ------------------------------
14242 // Angular expressions are generally considered safe because these expressions only have direct
14243 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
14244 // obtaining a reference to native JS functions such as the Function constructor.
14245 //
14246 // As an example, consider the following Angular expression:
14247 //
14248 //   {}.toString.constructor('alert("evil JS code")')
14249 //
14250 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
14251 // against the expression language, but not to prevent exploits that were enabled by exposing
14252 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
14253 // practice and therefore we are not even trying to protect against interaction with an object
14254 // explicitly exposed in this way.
14255 //
14256 // In general, it is not possible to access a Window object from an angular expression unless a
14257 // window or some DOM object that has a reference to window is published onto a Scope.
14258 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
14259 // native objects.
14260 //
14261 // See https://docs.angularjs.org/guide/security
14262
14263
14264 function ensureSafeMemberName(name, fullExpression) {
14265   if (name === '__defineGetter__' || name === '__defineSetter__'
14266       || name === '__lookupGetter__' || name === '__lookupSetter__'
14267       || name === '__proto__') {
14268     throw $parseMinErr('isecfld',
14269         'Attempting to access a disallowed field in Angular expressions! '
14270         + 'Expression: {0}', fullExpression);
14271   }
14272   return name;
14273 }
14274
14275 function getStringValue(name) {
14276   // Property names must be strings. This means that non-string objects cannot be used
14277   // as keys in an object. Any non-string object, including a number, is typecasted
14278   // into a string via the toString method.
14279   // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
14280   //
14281   // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
14282   // to a string. It's not always possible. If `name` is an object and its `toString` method is
14283   // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
14284   //
14285   // TypeError: Cannot convert object to primitive value
14286   //
14287   // For performance reasons, we don't catch this error here and allow it to propagate up the call
14288   // stack. Note that you'll get the same error in JavaScript if you try to access a property using
14289   // such a 'broken' object as a key.
14290   return name + '';
14291 }
14292
14293 function ensureSafeObject(obj, fullExpression) {
14294   // nifty check if obj is Function that is fast and works across iframes and other contexts
14295   if (obj) {
14296     if (obj.constructor === obj) {
14297       throw $parseMinErr('isecfn',
14298           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
14299           fullExpression);
14300     } else if (// isWindow(obj)
14301         obj.window === obj) {
14302       throw $parseMinErr('isecwindow',
14303           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
14304           fullExpression);
14305     } else if (// isElement(obj)
14306         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
14307       throw $parseMinErr('isecdom',
14308           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
14309           fullExpression);
14310     } else if (// block Object so that we can't get hold of dangerous Object.* methods
14311         obj === Object) {
14312       throw $parseMinErr('isecobj',
14313           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
14314           fullExpression);
14315     }
14316   }
14317   return obj;
14318 }
14319
14320 function ensureSafeFunction(obj, fullExpression) {
14321   if (obj) {
14322     if (obj.constructor === obj) {
14323       throw $parseMinErr('isecfn',
14324         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
14325         fullExpression);
14326     } else if (obj === CALL || obj === APPLY || obj === BIND) {
14327       throw $parseMinErr('isecff',
14328         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
14329         fullExpression);
14330     }
14331   }
14332 }
14333
14334 function ensureSafeAssignContext(obj, fullExpression) {
14335   if (obj) {
14336     if (obj === ARRAY_CTOR ||
14337         obj === BOOLEAN_CTOR ||
14338         obj === FUNCTION_CTOR ||
14339         obj === NUMBER_CTOR ||
14340         obj === OBJECT_CTOR ||
14341         obj === STRING_CTOR ||
14342         obj === ARRAY_CTOR_PROTO ||
14343         obj === BOOLEAN_CTOR_PROTO ||
14344         obj === FUNCTION_CTOR_PROTO ||
14345         obj === NUMBER_CTOR_PROTO ||
14346         obj === OBJECT_CTOR_PROTO ||
14347         obj === STRING_CTOR_PROTO) {
14348       throw $parseMinErr('isecaf',
14349         'Assigning to a constructor or its prototype is disallowed! Expression: {0}',
14350         fullExpression);
14351     }
14352   }
14353 }
14354
14355 var OPERATORS = createMap();
14356 forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
14357 var ESCAPE = {'n':'\n', 'f':'\f', 'r':'\r', 't':'\t', 'v':'\v', '\'':'\'', '"':'"'};
14358
14359
14360 /////////////////////////////////////////
14361
14362
14363 /**
14364  * @constructor
14365  */
14366 var Lexer = function Lexer(options) {
14367   this.options = options;
14368 };
14369
14370 Lexer.prototype = {
14371   constructor: Lexer,
14372
14373   lex: function(text) {
14374     this.text = text;
14375     this.index = 0;
14376     this.tokens = [];
14377
14378     while (this.index < this.text.length) {
14379       var ch = this.text.charAt(this.index);
14380       if (ch === '"' || ch === '\'') {
14381         this.readString(ch);
14382       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
14383         this.readNumber();
14384       } else if (this.isIdentifierStart(this.peekMultichar())) {
14385         this.readIdent();
14386       } else if (this.is(ch, '(){}[].,;:?')) {
14387         this.tokens.push({index: this.index, text: ch});
14388         this.index++;
14389       } else if (this.isWhitespace(ch)) {
14390         this.index++;
14391       } else {
14392         var ch2 = ch + this.peek();
14393         var ch3 = ch2 + this.peek(2);
14394         var op1 = OPERATORS[ch];
14395         var op2 = OPERATORS[ch2];
14396         var op3 = OPERATORS[ch3];
14397         if (op1 || op2 || op3) {
14398           var token = op3 ? ch3 : (op2 ? ch2 : ch);
14399           this.tokens.push({index: this.index, text: token, operator: true});
14400           this.index += token.length;
14401         } else {
14402           this.throwError('Unexpected next character ', this.index, this.index + 1);
14403         }
14404       }
14405     }
14406     return this.tokens;
14407   },
14408
14409   is: function(ch, chars) {
14410     return chars.indexOf(ch) !== -1;
14411   },
14412
14413   peek: function(i) {
14414     var num = i || 1;
14415     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
14416   },
14417
14418   isNumber: function(ch) {
14419     return ('0' <= ch && ch <= '9') && typeof ch === 'string';
14420   },
14421
14422   isWhitespace: function(ch) {
14423     // IE treats non-breaking space as \u00A0
14424     return (ch === ' ' || ch === '\r' || ch === '\t' ||
14425             ch === '\n' || ch === '\v' || ch === '\u00A0');
14426   },
14427
14428   isIdentifierStart: function(ch) {
14429     return this.options.isIdentifierStart ?
14430         this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
14431         this.isValidIdentifierStart(ch);
14432   },
14433
14434   isValidIdentifierStart: function(ch) {
14435     return ('a' <= ch && ch <= 'z' ||
14436             'A' <= ch && ch <= 'Z' ||
14437             '_' === ch || ch === '$');
14438   },
14439
14440   isIdentifierContinue: function(ch) {
14441     return this.options.isIdentifierContinue ?
14442         this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
14443         this.isValidIdentifierContinue(ch);
14444   },
14445
14446   isValidIdentifierContinue: function(ch, cp) {
14447     return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
14448   },
14449
14450   codePointAt: function(ch) {
14451     if (ch.length === 1) return ch.charCodeAt(0);
14452     // eslint-disable-next-line no-bitwise
14453     return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
14454   },
14455
14456   peekMultichar: function() {
14457     var ch = this.text.charAt(this.index);
14458     var peek = this.peek();
14459     if (!peek) {
14460       return ch;
14461     }
14462     var cp1 = ch.charCodeAt(0);
14463     var cp2 = peek.charCodeAt(0);
14464     if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
14465       return ch + peek;
14466     }
14467     return ch;
14468   },
14469
14470   isExpOperator: function(ch) {
14471     return (ch === '-' || ch === '+' || this.isNumber(ch));
14472   },
14473
14474   throwError: function(error, start, end) {
14475     end = end || this.index;
14476     var colStr = (isDefined(start)
14477             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
14478             : ' ' + end);
14479     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
14480         error, colStr, this.text);
14481   },
14482
14483   readNumber: function() {
14484     var number = '';
14485     var start = this.index;
14486     while (this.index < this.text.length) {
14487       var ch = lowercase(this.text.charAt(this.index));
14488       if (ch === '.' || this.isNumber(ch)) {
14489         number += ch;
14490       } else {
14491         var peekCh = this.peek();
14492         if (ch === 'e' && this.isExpOperator(peekCh)) {
14493           number += ch;
14494         } else if (this.isExpOperator(ch) &&
14495             peekCh && this.isNumber(peekCh) &&
14496             number.charAt(number.length - 1) === 'e') {
14497           number += ch;
14498         } else if (this.isExpOperator(ch) &&
14499             (!peekCh || !this.isNumber(peekCh)) &&
14500             number.charAt(number.length - 1) === 'e') {
14501           this.throwError('Invalid exponent');
14502         } else {
14503           break;
14504         }
14505       }
14506       this.index++;
14507     }
14508     this.tokens.push({
14509       index: start,
14510       text: number,
14511       constant: true,
14512       value: Number(number)
14513     });
14514   },
14515
14516   readIdent: function() {
14517     var start = this.index;
14518     this.index += this.peekMultichar().length;
14519     while (this.index < this.text.length) {
14520       var ch = this.peekMultichar();
14521       if (!this.isIdentifierContinue(ch)) {
14522         break;
14523       }
14524       this.index += ch.length;
14525     }
14526     this.tokens.push({
14527       index: start,
14528       text: this.text.slice(start, this.index),
14529       identifier: true
14530     });
14531   },
14532
14533   readString: function(quote) {
14534     var start = this.index;
14535     this.index++;
14536     var string = '';
14537     var rawString = quote;
14538     var escape = false;
14539     while (this.index < this.text.length) {
14540       var ch = this.text.charAt(this.index);
14541       rawString += ch;
14542       if (escape) {
14543         if (ch === 'u') {
14544           var hex = this.text.substring(this.index + 1, this.index + 5);
14545           if (!hex.match(/[\da-f]{4}/i)) {
14546             this.throwError('Invalid unicode escape [\\u' + hex + ']');
14547           }
14548           this.index += 4;
14549           string += String.fromCharCode(parseInt(hex, 16));
14550         } else {
14551           var rep = ESCAPE[ch];
14552           string = string + (rep || ch);
14553         }
14554         escape = false;
14555       } else if (ch === '\\') {
14556         escape = true;
14557       } else if (ch === quote) {
14558         this.index++;
14559         this.tokens.push({
14560           index: start,
14561           text: rawString,
14562           constant: true,
14563           value: string
14564         });
14565         return;
14566       } else {
14567         string += ch;
14568       }
14569       this.index++;
14570     }
14571     this.throwError('Unterminated quote', start);
14572   }
14573 };
14574
14575 var AST = function AST(lexer, options) {
14576   this.lexer = lexer;
14577   this.options = options;
14578 };
14579
14580 AST.Program = 'Program';
14581 AST.ExpressionStatement = 'ExpressionStatement';
14582 AST.AssignmentExpression = 'AssignmentExpression';
14583 AST.ConditionalExpression = 'ConditionalExpression';
14584 AST.LogicalExpression = 'LogicalExpression';
14585 AST.BinaryExpression = 'BinaryExpression';
14586 AST.UnaryExpression = 'UnaryExpression';
14587 AST.CallExpression = 'CallExpression';
14588 AST.MemberExpression = 'MemberExpression';
14589 AST.Identifier = 'Identifier';
14590 AST.Literal = 'Literal';
14591 AST.ArrayExpression = 'ArrayExpression';
14592 AST.Property = 'Property';
14593 AST.ObjectExpression = 'ObjectExpression';
14594 AST.ThisExpression = 'ThisExpression';
14595 AST.LocalsExpression = 'LocalsExpression';
14596
14597 // Internal use only
14598 AST.NGValueParameter = 'NGValueParameter';
14599
14600 AST.prototype = {
14601   ast: function(text) {
14602     this.text = text;
14603     this.tokens = this.lexer.lex(text);
14604
14605     var value = this.program();
14606
14607     if (this.tokens.length !== 0) {
14608       this.throwError('is an unexpected token', this.tokens[0]);
14609     }
14610
14611     return value;
14612   },
14613
14614   program: function() {
14615     var body = [];
14616     while (true) {
14617       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
14618         body.push(this.expressionStatement());
14619       if (!this.expect(';')) {
14620         return { type: AST.Program, body: body};
14621       }
14622     }
14623   },
14624
14625   expressionStatement: function() {
14626     return { type: AST.ExpressionStatement, expression: this.filterChain() };
14627   },
14628
14629   filterChain: function() {
14630     var left = this.expression();
14631     while (this.expect('|')) {
14632       left = this.filter(left);
14633     }
14634     return left;
14635   },
14636
14637   expression: function() {
14638     return this.assignment();
14639   },
14640
14641   assignment: function() {
14642     var result = this.ternary();
14643     if (this.expect('=')) {
14644       if (!isAssignable(result)) {
14645         throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
14646       }
14647
14648       result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
14649     }
14650     return result;
14651   },
14652
14653   ternary: function() {
14654     var test = this.logicalOR();
14655     var alternate;
14656     var consequent;
14657     if (this.expect('?')) {
14658       alternate = this.expression();
14659       if (this.consume(':')) {
14660         consequent = this.expression();
14661         return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
14662       }
14663     }
14664     return test;
14665   },
14666
14667   logicalOR: function() {
14668     var left = this.logicalAND();
14669     while (this.expect('||')) {
14670       left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
14671     }
14672     return left;
14673   },
14674
14675   logicalAND: function() {
14676     var left = this.equality();
14677     while (this.expect('&&')) {
14678       left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
14679     }
14680     return left;
14681   },
14682
14683   equality: function() {
14684     var left = this.relational();
14685     var token;
14686     while ((token = this.expect('==','!=','===','!=='))) {
14687       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
14688     }
14689     return left;
14690   },
14691
14692   relational: function() {
14693     var left = this.additive();
14694     var token;
14695     while ((token = this.expect('<', '>', '<=', '>='))) {
14696       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
14697     }
14698     return left;
14699   },
14700
14701   additive: function() {
14702     var left = this.multiplicative();
14703     var token;
14704     while ((token = this.expect('+','-'))) {
14705       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
14706     }
14707     return left;
14708   },
14709
14710   multiplicative: function() {
14711     var left = this.unary();
14712     var token;
14713     while ((token = this.expect('*','/','%'))) {
14714       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
14715     }
14716     return left;
14717   },
14718
14719   unary: function() {
14720     var token;
14721     if ((token = this.expect('+', '-', '!'))) {
14722       return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
14723     } else {
14724       return this.primary();
14725     }
14726   },
14727
14728   primary: function() {
14729     var primary;
14730     if (this.expect('(')) {
14731       primary = this.filterChain();
14732       this.consume(')');
14733     } else if (this.expect('[')) {
14734       primary = this.arrayDeclaration();
14735     } else if (this.expect('{')) {
14736       primary = this.object();
14737     } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
14738       primary = copy(this.selfReferential[this.consume().text]);
14739     } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
14740       primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
14741     } else if (this.peek().identifier) {
14742       primary = this.identifier();
14743     } else if (this.peek().constant) {
14744       primary = this.constant();
14745     } else {
14746       this.throwError('not a primary expression', this.peek());
14747     }
14748
14749     var next;
14750     while ((next = this.expect('(', '[', '.'))) {
14751       if (next.text === '(') {
14752         primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
14753         this.consume(')');
14754       } else if (next.text === '[') {
14755         primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
14756         this.consume(']');
14757       } else if (next.text === '.') {
14758         primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
14759       } else {
14760         this.throwError('IMPOSSIBLE');
14761       }
14762     }
14763     return primary;
14764   },
14765
14766   filter: function(baseExpression) {
14767     var args = [baseExpression];
14768     var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
14769
14770     while (this.expect(':')) {
14771       args.push(this.expression());
14772     }
14773
14774     return result;
14775   },
14776
14777   parseArguments: function() {
14778     var args = [];
14779     if (this.peekToken().text !== ')') {
14780       do {
14781         args.push(this.filterChain());
14782       } while (this.expect(','));
14783     }
14784     return args;
14785   },
14786
14787   identifier: function() {
14788     var token = this.consume();
14789     if (!token.identifier) {
14790       this.throwError('is not a valid identifier', token);
14791     }
14792     return { type: AST.Identifier, name: token.text };
14793   },
14794
14795   constant: function() {
14796     // TODO check that it is a constant
14797     return { type: AST.Literal, value: this.consume().value };
14798   },
14799
14800   arrayDeclaration: function() {
14801     var elements = [];
14802     if (this.peekToken().text !== ']') {
14803       do {
14804         if (this.peek(']')) {
14805           // Support trailing commas per ES5.1.
14806           break;
14807         }
14808         elements.push(this.expression());
14809       } while (this.expect(','));
14810     }
14811     this.consume(']');
14812
14813     return { type: AST.ArrayExpression, elements: elements };
14814   },
14815
14816   object: function() {
14817     var properties = [], property;
14818     if (this.peekToken().text !== '}') {
14819       do {
14820         if (this.peek('}')) {
14821           // Support trailing commas per ES5.1.
14822           break;
14823         }
14824         property = {type: AST.Property, kind: 'init'};
14825         if (this.peek().constant) {
14826           property.key = this.constant();
14827           property.computed = false;
14828           this.consume(':');
14829           property.value = this.expression();
14830         } else if (this.peek().identifier) {
14831           property.key = this.identifier();
14832           property.computed = false;
14833           if (this.peek(':')) {
14834             this.consume(':');
14835             property.value = this.expression();
14836           } else {
14837             property.value = property.key;
14838           }
14839         } else if (this.peek('[')) {
14840           this.consume('[');
14841           property.key = this.expression();
14842           this.consume(']');
14843           property.computed = true;
14844           this.consume(':');
14845           property.value = this.expression();
14846         } else {
14847           this.throwError('invalid key', this.peek());
14848         }
14849         properties.push(property);
14850       } while (this.expect(','));
14851     }
14852     this.consume('}');
14853
14854     return {type: AST.ObjectExpression, properties: properties };
14855   },
14856
14857   throwError: function(msg, token) {
14858     throw $parseMinErr('syntax',
14859         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
14860           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
14861   },
14862
14863   consume: function(e1) {
14864     if (this.tokens.length === 0) {
14865       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
14866     }
14867
14868     var token = this.expect(e1);
14869     if (!token) {
14870       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
14871     }
14872     return token;
14873   },
14874
14875   peekToken: function() {
14876     if (this.tokens.length === 0) {
14877       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
14878     }
14879     return this.tokens[0];
14880   },
14881
14882   peek: function(e1, e2, e3, e4) {
14883     return this.peekAhead(0, e1, e2, e3, e4);
14884   },
14885
14886   peekAhead: function(i, e1, e2, e3, e4) {
14887     if (this.tokens.length > i) {
14888       var token = this.tokens[i];
14889       var t = token.text;
14890       if (t === e1 || t === e2 || t === e3 || t === e4 ||
14891           (!e1 && !e2 && !e3 && !e4)) {
14892         return token;
14893       }
14894     }
14895     return false;
14896   },
14897
14898   expect: function(e1, e2, e3, e4) {
14899     var token = this.peek(e1, e2, e3, e4);
14900     if (token) {
14901       this.tokens.shift();
14902       return token;
14903     }
14904     return false;
14905   },
14906
14907   selfReferential: {
14908     'this': {type: AST.ThisExpression },
14909     '$locals': {type: AST.LocalsExpression }
14910   }
14911 };
14912
14913 function ifDefined(v, d) {
14914   return typeof v !== 'undefined' ? v : d;
14915 }
14916
14917 function plusFn(l, r) {
14918   if (typeof l === 'undefined') return r;
14919   if (typeof r === 'undefined') return l;
14920   return l + r;
14921 }
14922
14923 function isStateless($filter, filterName) {
14924   var fn = $filter(filterName);
14925   return !fn.$stateful;
14926 }
14927
14928 function findConstantAndWatchExpressions(ast, $filter) {
14929   var allConstants;
14930   var argsToWatch;
14931   var isStatelessFilter;
14932   switch (ast.type) {
14933   case AST.Program:
14934     allConstants = true;
14935     forEach(ast.body, function(expr) {
14936       findConstantAndWatchExpressions(expr.expression, $filter);
14937       allConstants = allConstants && expr.expression.constant;
14938     });
14939     ast.constant = allConstants;
14940     break;
14941   case AST.Literal:
14942     ast.constant = true;
14943     ast.toWatch = [];
14944     break;
14945   case AST.UnaryExpression:
14946     findConstantAndWatchExpressions(ast.argument, $filter);
14947     ast.constant = ast.argument.constant;
14948     ast.toWatch = ast.argument.toWatch;
14949     break;
14950   case AST.BinaryExpression:
14951     findConstantAndWatchExpressions(ast.left, $filter);
14952     findConstantAndWatchExpressions(ast.right, $filter);
14953     ast.constant = ast.left.constant && ast.right.constant;
14954     ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
14955     break;
14956   case AST.LogicalExpression:
14957     findConstantAndWatchExpressions(ast.left, $filter);
14958     findConstantAndWatchExpressions(ast.right, $filter);
14959     ast.constant = ast.left.constant && ast.right.constant;
14960     ast.toWatch = ast.constant ? [] : [ast];
14961     break;
14962   case AST.ConditionalExpression:
14963     findConstantAndWatchExpressions(ast.test, $filter);
14964     findConstantAndWatchExpressions(ast.alternate, $filter);
14965     findConstantAndWatchExpressions(ast.consequent, $filter);
14966     ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
14967     ast.toWatch = ast.constant ? [] : [ast];
14968     break;
14969   case AST.Identifier:
14970     ast.constant = false;
14971     ast.toWatch = [ast];
14972     break;
14973   case AST.MemberExpression:
14974     findConstantAndWatchExpressions(ast.object, $filter);
14975     if (ast.computed) {
14976       findConstantAndWatchExpressions(ast.property, $filter);
14977     }
14978     ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
14979     ast.toWatch = [ast];
14980     break;
14981   case AST.CallExpression:
14982     isStatelessFilter = ast.filter ? isStateless($filter, ast.callee.name) : false;
14983     allConstants = isStatelessFilter;
14984     argsToWatch = [];
14985     forEach(ast.arguments, function(expr) {
14986       findConstantAndWatchExpressions(expr, $filter);
14987       allConstants = allConstants && expr.constant;
14988       if (!expr.constant) {
14989         argsToWatch.push.apply(argsToWatch, expr.toWatch);
14990       }
14991     });
14992     ast.constant = allConstants;
14993     ast.toWatch = isStatelessFilter ? argsToWatch : [ast];
14994     break;
14995   case AST.AssignmentExpression:
14996     findConstantAndWatchExpressions(ast.left, $filter);
14997     findConstantAndWatchExpressions(ast.right, $filter);
14998     ast.constant = ast.left.constant && ast.right.constant;
14999     ast.toWatch = [ast];
15000     break;
15001   case AST.ArrayExpression:
15002     allConstants = true;
15003     argsToWatch = [];
15004     forEach(ast.elements, function(expr) {
15005       findConstantAndWatchExpressions(expr, $filter);
15006       allConstants = allConstants && expr.constant;
15007       if (!expr.constant) {
15008         argsToWatch.push.apply(argsToWatch, expr.toWatch);
15009       }
15010     });
15011     ast.constant = allConstants;
15012     ast.toWatch = argsToWatch;
15013     break;
15014   case AST.ObjectExpression:
15015     allConstants = true;
15016     argsToWatch = [];
15017     forEach(ast.properties, function(property) {
15018       findConstantAndWatchExpressions(property.value, $filter);
15019       allConstants = allConstants && property.value.constant && !property.computed;
15020       if (!property.value.constant) {
15021         argsToWatch.push.apply(argsToWatch, property.value.toWatch);
15022       }
15023     });
15024     ast.constant = allConstants;
15025     ast.toWatch = argsToWatch;
15026     break;
15027   case AST.ThisExpression:
15028     ast.constant = false;
15029     ast.toWatch = [];
15030     break;
15031   case AST.LocalsExpression:
15032     ast.constant = false;
15033     ast.toWatch = [];
15034     break;
15035   }
15036 }
15037
15038 function getInputs(body) {
15039   if (body.length !== 1) return;
15040   var lastExpression = body[0].expression;
15041   var candidate = lastExpression.toWatch;
15042   if (candidate.length !== 1) return candidate;
15043   return candidate[0] !== lastExpression ? candidate : undefined;
15044 }
15045
15046 function isAssignable(ast) {
15047   return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
15048 }
15049
15050 function assignableAST(ast) {
15051   if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
15052     return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
15053   }
15054 }
15055
15056 function isLiteral(ast) {
15057   return ast.body.length === 0 ||
15058       ast.body.length === 1 && (
15059       ast.body[0].expression.type === AST.Literal ||
15060       ast.body[0].expression.type === AST.ArrayExpression ||
15061       ast.body[0].expression.type === AST.ObjectExpression);
15062 }
15063
15064 function isConstant(ast) {
15065   return ast.constant;
15066 }
15067
15068 function ASTCompiler(astBuilder, $filter) {
15069   this.astBuilder = astBuilder;
15070   this.$filter = $filter;
15071 }
15072
15073 ASTCompiler.prototype = {
15074   compile: function(expression, expensiveChecks) {
15075     var self = this;
15076     var ast = this.astBuilder.ast(expression);
15077     this.state = {
15078       nextId: 0,
15079       filters: {},
15080       expensiveChecks: expensiveChecks,
15081       fn: {vars: [], body: [], own: {}},
15082       assign: {vars: [], body: [], own: {}},
15083       inputs: []
15084     };
15085     findConstantAndWatchExpressions(ast, self.$filter);
15086     var extra = '';
15087     var assignable;
15088     this.stage = 'assign';
15089     if ((assignable = assignableAST(ast))) {
15090       this.state.computing = 'assign';
15091       var result = this.nextId();
15092       this.recurse(assignable, result);
15093       this.return_(result);
15094       extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
15095     }
15096     var toWatch = getInputs(ast.body);
15097     self.stage = 'inputs';
15098     forEach(toWatch, function(watch, key) {
15099       var fnKey = 'fn' + key;
15100       self.state[fnKey] = {vars: [], body: [], own: {}};
15101       self.state.computing = fnKey;
15102       var intoId = self.nextId();
15103       self.recurse(watch, intoId);
15104       self.return_(intoId);
15105       self.state.inputs.push(fnKey);
15106       watch.watchId = key;
15107     });
15108     this.state.computing = 'fn';
15109     this.stage = 'main';
15110     this.recurse(ast);
15111     var fnString =
15112       // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
15113       // This is a workaround for this until we do a better job at only removing the prefix only when we should.
15114       '"' + this.USE + ' ' + this.STRICT + '";\n' +
15115       this.filterPrefix() +
15116       'var fn=' + this.generateFunction('fn', 's,l,a,i') +
15117       extra +
15118       this.watchFns() +
15119       'return fn;';
15120
15121     // eslint-disable-next-line no-new-func
15122     var fn = (new Function('$filter',
15123         'ensureSafeMemberName',
15124         'ensureSafeObject',
15125         'ensureSafeFunction',
15126         'getStringValue',
15127         'ensureSafeAssignContext',
15128         'ifDefined',
15129         'plus',
15130         'text',
15131         fnString))(
15132           this.$filter,
15133           ensureSafeMemberName,
15134           ensureSafeObject,
15135           ensureSafeFunction,
15136           getStringValue,
15137           ensureSafeAssignContext,
15138           ifDefined,
15139           plusFn,
15140           expression);
15141     this.state = this.stage = undefined;
15142     fn.literal = isLiteral(ast);
15143     fn.constant = isConstant(ast);
15144     return fn;
15145   },
15146
15147   USE: 'use',
15148
15149   STRICT: 'strict',
15150
15151   watchFns: function() {
15152     var result = [];
15153     var fns = this.state.inputs;
15154     var self = this;
15155     forEach(fns, function(name) {
15156       result.push('var ' + name + '=' + self.generateFunction(name, 's'));
15157     });
15158     if (fns.length) {
15159       result.push('fn.inputs=[' + fns.join(',') + '];');
15160     }
15161     return result.join('');
15162   },
15163
15164   generateFunction: function(name, params) {
15165     return 'function(' + params + '){' +
15166         this.varsPrefix(name) +
15167         this.body(name) +
15168         '};';
15169   },
15170
15171   filterPrefix: function() {
15172     var parts = [];
15173     var self = this;
15174     forEach(this.state.filters, function(id, filter) {
15175       parts.push(id + '=$filter(' + self.escape(filter) + ')');
15176     });
15177     if (parts.length) return 'var ' + parts.join(',') + ';';
15178     return '';
15179   },
15180
15181   varsPrefix: function(section) {
15182     return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
15183   },
15184
15185   body: function(section) {
15186     return this.state[section].body.join('');
15187   },
15188
15189   recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
15190     var left, right, self = this, args, expression, computed;
15191     recursionFn = recursionFn || noop;
15192     if (!skipWatchIdCheck && isDefined(ast.watchId)) {
15193       intoId = intoId || this.nextId();
15194       this.if_('i',
15195         this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
15196         this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
15197       );
15198       return;
15199     }
15200     switch (ast.type) {
15201     case AST.Program:
15202       forEach(ast.body, function(expression, pos) {
15203         self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
15204         if (pos !== ast.body.length - 1) {
15205           self.current().body.push(right, ';');
15206         } else {
15207           self.return_(right);
15208         }
15209       });
15210       break;
15211     case AST.Literal:
15212       expression = this.escape(ast.value);
15213       this.assign(intoId, expression);
15214       recursionFn(expression);
15215       break;
15216     case AST.UnaryExpression:
15217       this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
15218       expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
15219       this.assign(intoId, expression);
15220       recursionFn(expression);
15221       break;
15222     case AST.BinaryExpression:
15223       this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
15224       this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
15225       if (ast.operator === '+') {
15226         expression = this.plus(left, right);
15227       } else if (ast.operator === '-') {
15228         expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
15229       } else {
15230         expression = '(' + left + ')' + ast.operator + '(' + right + ')';
15231       }
15232       this.assign(intoId, expression);
15233       recursionFn(expression);
15234       break;
15235     case AST.LogicalExpression:
15236       intoId = intoId || this.nextId();
15237       self.recurse(ast.left, intoId);
15238       self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
15239       recursionFn(intoId);
15240       break;
15241     case AST.ConditionalExpression:
15242       intoId = intoId || this.nextId();
15243       self.recurse(ast.test, intoId);
15244       self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
15245       recursionFn(intoId);
15246       break;
15247     case AST.Identifier:
15248       intoId = intoId || this.nextId();
15249       if (nameId) {
15250         nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
15251         nameId.computed = false;
15252         nameId.name = ast.name;
15253       }
15254       ensureSafeMemberName(ast.name);
15255       self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
15256         function() {
15257           self.if_(self.stage === 'inputs' || 's', function() {
15258             if (create && create !== 1) {
15259               self.if_(
15260                 self.not(self.nonComputedMember('s', ast.name)),
15261                 self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
15262             }
15263             self.assign(intoId, self.nonComputedMember('s', ast.name));
15264           });
15265         }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
15266         );
15267       if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
15268         self.addEnsureSafeObject(intoId);
15269       }
15270       recursionFn(intoId);
15271       break;
15272     case AST.MemberExpression:
15273       left = nameId && (nameId.context = this.nextId()) || this.nextId();
15274       intoId = intoId || this.nextId();
15275       self.recurse(ast.object, left, undefined, function() {
15276         self.if_(self.notNull(left), function() {
15277           if (create && create !== 1) {
15278             self.addEnsureSafeAssignContext(left);
15279           }
15280           if (ast.computed) {
15281             right = self.nextId();
15282             self.recurse(ast.property, right);
15283             self.getStringValue(right);
15284             self.addEnsureSafeMemberName(right);
15285             if (create && create !== 1) {
15286               self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
15287             }
15288             expression = self.ensureSafeObject(self.computedMember(left, right));
15289             self.assign(intoId, expression);
15290             if (nameId) {
15291               nameId.computed = true;
15292               nameId.name = right;
15293             }
15294           } else {
15295             ensureSafeMemberName(ast.property.name);
15296             if (create && create !== 1) {
15297               self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
15298             }
15299             expression = self.nonComputedMember(left, ast.property.name);
15300             if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
15301               expression = self.ensureSafeObject(expression);
15302             }
15303             self.assign(intoId, expression);
15304             if (nameId) {
15305               nameId.computed = false;
15306               nameId.name = ast.property.name;
15307             }
15308           }
15309         }, function() {
15310           self.assign(intoId, 'undefined');
15311         });
15312         recursionFn(intoId);
15313       }, !!create);
15314       break;
15315     case AST.CallExpression:
15316       intoId = intoId || this.nextId();
15317       if (ast.filter) {
15318         right = self.filter(ast.callee.name);
15319         args = [];
15320         forEach(ast.arguments, function(expr) {
15321           var argument = self.nextId();
15322           self.recurse(expr, argument);
15323           args.push(argument);
15324         });
15325         expression = right + '(' + args.join(',') + ')';
15326         self.assign(intoId, expression);
15327         recursionFn(intoId);
15328       } else {
15329         right = self.nextId();
15330         left = {};
15331         args = [];
15332         self.recurse(ast.callee, right, left, function() {
15333           self.if_(self.notNull(right), function() {
15334             self.addEnsureSafeFunction(right);
15335             forEach(ast.arguments, function(expr) {
15336               self.recurse(expr, self.nextId(), undefined, function(argument) {
15337                 args.push(self.ensureSafeObject(argument));
15338               });
15339             });
15340             if (left.name) {
15341               if (!self.state.expensiveChecks) {
15342                 self.addEnsureSafeObject(left.context);
15343               }
15344               expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
15345             } else {
15346               expression = right + '(' + args.join(',') + ')';
15347             }
15348             expression = self.ensureSafeObject(expression);
15349             self.assign(intoId, expression);
15350           }, function() {
15351             self.assign(intoId, 'undefined');
15352           });
15353           recursionFn(intoId);
15354         });
15355       }
15356       break;
15357     case AST.AssignmentExpression:
15358       right = this.nextId();
15359       left = {};
15360       this.recurse(ast.left, undefined, left, function() {
15361         self.if_(self.notNull(left.context), function() {
15362           self.recurse(ast.right, right);
15363           self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
15364           self.addEnsureSafeAssignContext(left.context);
15365           expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
15366           self.assign(intoId, expression);
15367           recursionFn(intoId || expression);
15368         });
15369       }, 1);
15370       break;
15371     case AST.ArrayExpression:
15372       args = [];
15373       forEach(ast.elements, function(expr) {
15374         self.recurse(expr, self.nextId(), undefined, function(argument) {
15375           args.push(argument);
15376         });
15377       });
15378       expression = '[' + args.join(',') + ']';
15379       this.assign(intoId, expression);
15380       recursionFn(expression);
15381       break;
15382     case AST.ObjectExpression:
15383       args = [];
15384       computed = false;
15385       forEach(ast.properties, function(property) {
15386         if (property.computed) {
15387           computed = true;
15388         }
15389       });
15390       if (computed) {
15391         intoId = intoId || this.nextId();
15392         this.assign(intoId, '{}');
15393         forEach(ast.properties, function(property) {
15394           if (property.computed) {
15395             left = self.nextId();
15396             self.recurse(property.key, left);
15397           } else {
15398             left = property.key.type === AST.Identifier ?
15399                        property.key.name :
15400                        ('' + property.key.value);
15401           }
15402           right = self.nextId();
15403           self.recurse(property.value, right);
15404           self.assign(self.member(intoId, left, property.computed), right);
15405         });
15406       } else {
15407         forEach(ast.properties, function(property) {
15408           self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) {
15409             args.push(self.escape(
15410                 property.key.type === AST.Identifier ? property.key.name :
15411                   ('' + property.key.value)) +
15412                 ':' + expr);
15413           });
15414         });
15415         expression = '{' + args.join(',') + '}';
15416         this.assign(intoId, expression);
15417       }
15418       recursionFn(intoId || expression);
15419       break;
15420     case AST.ThisExpression:
15421       this.assign(intoId, 's');
15422       recursionFn('s');
15423       break;
15424     case AST.LocalsExpression:
15425       this.assign(intoId, 'l');
15426       recursionFn('l');
15427       break;
15428     case AST.NGValueParameter:
15429       this.assign(intoId, 'v');
15430       recursionFn('v');
15431       break;
15432     }
15433   },
15434
15435   getHasOwnProperty: function(element, property) {
15436     var key = element + '.' + property;
15437     var own = this.current().own;
15438     if (!own.hasOwnProperty(key)) {
15439       own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
15440     }
15441     return own[key];
15442   },
15443
15444   assign: function(id, value) {
15445     if (!id) return;
15446     this.current().body.push(id, '=', value, ';');
15447     return id;
15448   },
15449
15450   filter: function(filterName) {
15451     if (!this.state.filters.hasOwnProperty(filterName)) {
15452       this.state.filters[filterName] = this.nextId(true);
15453     }
15454     return this.state.filters[filterName];
15455   },
15456
15457   ifDefined: function(id, defaultValue) {
15458     return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
15459   },
15460
15461   plus: function(left, right) {
15462     return 'plus(' + left + ',' + right + ')';
15463   },
15464
15465   return_: function(id) {
15466     this.current().body.push('return ', id, ';');
15467   },
15468
15469   if_: function(test, alternate, consequent) {
15470     if (test === true) {
15471       alternate();
15472     } else {
15473       var body = this.current().body;
15474       body.push('if(', test, '){');
15475       alternate();
15476       body.push('}');
15477       if (consequent) {
15478         body.push('else{');
15479         consequent();
15480         body.push('}');
15481       }
15482     }
15483   },
15484
15485   not: function(expression) {
15486     return '!(' + expression + ')';
15487   },
15488
15489   notNull: function(expression) {
15490     return expression + '!=null';
15491   },
15492
15493   nonComputedMember: function(left, right) {
15494     var SAFE_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
15495     var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
15496     if (SAFE_IDENTIFIER.test(right)) {
15497       return left + '.' + right;
15498     } else {
15499       return left  + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
15500     }
15501   },
15502
15503   computedMember: function(left, right) {
15504     return left + '[' + right + ']';
15505   },
15506
15507   member: function(left, right, computed) {
15508     if (computed) return this.computedMember(left, right);
15509     return this.nonComputedMember(left, right);
15510   },
15511
15512   addEnsureSafeObject: function(item) {
15513     this.current().body.push(this.ensureSafeObject(item), ';');
15514   },
15515
15516   addEnsureSafeMemberName: function(item) {
15517     this.current().body.push(this.ensureSafeMemberName(item), ';');
15518   },
15519
15520   addEnsureSafeFunction: function(item) {
15521     this.current().body.push(this.ensureSafeFunction(item), ';');
15522   },
15523
15524   addEnsureSafeAssignContext: function(item) {
15525     this.current().body.push(this.ensureSafeAssignContext(item), ';');
15526   },
15527
15528   ensureSafeObject: function(item) {
15529     return 'ensureSafeObject(' + item + ',text)';
15530   },
15531
15532   ensureSafeMemberName: function(item) {
15533     return 'ensureSafeMemberName(' + item + ',text)';
15534   },
15535
15536   ensureSafeFunction: function(item) {
15537     return 'ensureSafeFunction(' + item + ',text)';
15538   },
15539
15540   getStringValue: function(item) {
15541     this.assign(item, 'getStringValue(' + item + ')');
15542   },
15543
15544   ensureSafeAssignContext: function(item) {
15545     return 'ensureSafeAssignContext(' + item + ',text)';
15546   },
15547
15548   lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
15549     var self = this;
15550     return function() {
15551       self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
15552     };
15553   },
15554
15555   lazyAssign: function(id, value) {
15556     var self = this;
15557     return function() {
15558       self.assign(id, value);
15559     };
15560   },
15561
15562   stringEscapeRegex: /[^ a-zA-Z0-9]/g,
15563
15564   stringEscapeFn: function(c) {
15565     return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
15566   },
15567
15568   escape: function(value) {
15569     if (isString(value)) return '\'' + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + '\'';
15570     if (isNumber(value)) return value.toString();
15571     if (value === true) return 'true';
15572     if (value === false) return 'false';
15573     if (value === null) return 'null';
15574     if (typeof value === 'undefined') return 'undefined';
15575
15576     throw $parseMinErr('esc', 'IMPOSSIBLE');
15577   },
15578
15579   nextId: function(skip, init) {
15580     var id = 'v' + (this.state.nextId++);
15581     if (!skip) {
15582       this.current().vars.push(id + (init ? '=' + init : ''));
15583     }
15584     return id;
15585   },
15586
15587   current: function() {
15588     return this.state[this.state.computing];
15589   }
15590 };
15591
15592
15593 function ASTInterpreter(astBuilder, $filter) {
15594   this.astBuilder = astBuilder;
15595   this.$filter = $filter;
15596 }
15597
15598 ASTInterpreter.prototype = {
15599   compile: function(expression, expensiveChecks) {
15600     var self = this;
15601     var ast = this.astBuilder.ast(expression);
15602     this.expression = expression;
15603     this.expensiveChecks = expensiveChecks;
15604     findConstantAndWatchExpressions(ast, self.$filter);
15605     var assignable;
15606     var assign;
15607     if ((assignable = assignableAST(ast))) {
15608       assign = this.recurse(assignable);
15609     }
15610     var toWatch = getInputs(ast.body);
15611     var inputs;
15612     if (toWatch) {
15613       inputs = [];
15614       forEach(toWatch, function(watch, key) {
15615         var input = self.recurse(watch);
15616         watch.input = input;
15617         inputs.push(input);
15618         watch.watchId = key;
15619       });
15620     }
15621     var expressions = [];
15622     forEach(ast.body, function(expression) {
15623       expressions.push(self.recurse(expression.expression));
15624     });
15625     var fn = ast.body.length === 0 ? noop :
15626              ast.body.length === 1 ? expressions[0] :
15627              function(scope, locals) {
15628                var lastValue;
15629                forEach(expressions, function(exp) {
15630                  lastValue = exp(scope, locals);
15631                });
15632                return lastValue;
15633              };
15634     if (assign) {
15635       fn.assign = function(scope, value, locals) {
15636         return assign(scope, locals, value);
15637       };
15638     }
15639     if (inputs) {
15640       fn.inputs = inputs;
15641     }
15642     fn.literal = isLiteral(ast);
15643     fn.constant = isConstant(ast);
15644     return fn;
15645   },
15646
15647   recurse: function(ast, context, create) {
15648     var left, right, self = this, args;
15649     if (ast.input) {
15650       return this.inputs(ast.input, ast.watchId);
15651     }
15652     switch (ast.type) {
15653     case AST.Literal:
15654       return this.value(ast.value, context);
15655     case AST.UnaryExpression:
15656       right = this.recurse(ast.argument);
15657       return this['unary' + ast.operator](right, context);
15658     case AST.BinaryExpression:
15659       left = this.recurse(ast.left);
15660       right = this.recurse(ast.right);
15661       return this['binary' + ast.operator](left, right, context);
15662     case AST.LogicalExpression:
15663       left = this.recurse(ast.left);
15664       right = this.recurse(ast.right);
15665       return this['binary' + ast.operator](left, right, context);
15666     case AST.ConditionalExpression:
15667       return this['ternary?:'](
15668         this.recurse(ast.test),
15669         this.recurse(ast.alternate),
15670         this.recurse(ast.consequent),
15671         context
15672       );
15673     case AST.Identifier:
15674       ensureSafeMemberName(ast.name, self.expression);
15675       return self.identifier(ast.name,
15676                              self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
15677                              context, create, self.expression);
15678     case AST.MemberExpression:
15679       left = this.recurse(ast.object, false, !!create);
15680       if (!ast.computed) {
15681         ensureSafeMemberName(ast.property.name, self.expression);
15682         right = ast.property.name;
15683       }
15684       if (ast.computed) right = this.recurse(ast.property);
15685       return ast.computed ?
15686         this.computedMember(left, right, context, create, self.expression) :
15687         this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
15688     case AST.CallExpression:
15689       args = [];
15690       forEach(ast.arguments, function(expr) {
15691         args.push(self.recurse(expr));
15692       });
15693       if (ast.filter) right = this.$filter(ast.callee.name);
15694       if (!ast.filter) right = this.recurse(ast.callee, true);
15695       return ast.filter ?
15696         function(scope, locals, assign, inputs) {
15697           var values = [];
15698           for (var i = 0; i < args.length; ++i) {
15699             values.push(args[i](scope, locals, assign, inputs));
15700           }
15701           var value = right.apply(undefined, values, inputs);
15702           return context ? {context: undefined, name: undefined, value: value} : value;
15703         } :
15704         function(scope, locals, assign, inputs) {
15705           var rhs = right(scope, locals, assign, inputs);
15706           var value;
15707           if (rhs.value != null) {
15708             ensureSafeObject(rhs.context, self.expression);
15709             ensureSafeFunction(rhs.value, self.expression);
15710             var values = [];
15711             for (var i = 0; i < args.length; ++i) {
15712               values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
15713             }
15714             value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
15715           }
15716           return context ? {value: value} : value;
15717         };
15718     case AST.AssignmentExpression:
15719       left = this.recurse(ast.left, true, 1);
15720       right = this.recurse(ast.right);
15721       return function(scope, locals, assign, inputs) {
15722         var lhs = left(scope, locals, assign, inputs);
15723         var rhs = right(scope, locals, assign, inputs);
15724         ensureSafeObject(lhs.value, self.expression);
15725         ensureSafeAssignContext(lhs.context);
15726         lhs.context[lhs.name] = rhs;
15727         return context ? {value: rhs} : rhs;
15728       };
15729     case AST.ArrayExpression:
15730       args = [];
15731       forEach(ast.elements, function(expr) {
15732         args.push(self.recurse(expr));
15733       });
15734       return function(scope, locals, assign, inputs) {
15735         var value = [];
15736         for (var i = 0; i < args.length; ++i) {
15737           value.push(args[i](scope, locals, assign, inputs));
15738         }
15739         return context ? {value: value} : value;
15740       };
15741     case AST.ObjectExpression:
15742       args = [];
15743       forEach(ast.properties, function(property) {
15744         if (property.computed) {
15745           args.push({key: self.recurse(property.key),
15746                      computed: true,
15747                      value: self.recurse(property.value)
15748           });
15749         } else {
15750           args.push({key: property.key.type === AST.Identifier ?
15751                           property.key.name :
15752                           ('' + property.key.value),
15753                      computed: false,
15754                      value: self.recurse(property.value)
15755           });
15756         }
15757       });
15758       return function(scope, locals, assign, inputs) {
15759         var value = {};
15760         for (var i = 0; i < args.length; ++i) {
15761           if (args[i].computed) {
15762             value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs);
15763           } else {
15764             value[args[i].key] = args[i].value(scope, locals, assign, inputs);
15765           }
15766         }
15767         return context ? {value: value} : value;
15768       };
15769     case AST.ThisExpression:
15770       return function(scope) {
15771         return context ? {value: scope} : scope;
15772       };
15773     case AST.LocalsExpression:
15774       return function(scope, locals) {
15775         return context ? {value: locals} : locals;
15776       };
15777     case AST.NGValueParameter:
15778       return function(scope, locals, assign) {
15779         return context ? {value: assign} : assign;
15780       };
15781     }
15782   },
15783
15784   'unary+': function(argument, context) {
15785     return function(scope, locals, assign, inputs) {
15786       var arg = argument(scope, locals, assign, inputs);
15787       if (isDefined(arg)) {
15788         arg = +arg;
15789       } else {
15790         arg = 0;
15791       }
15792       return context ? {value: arg} : arg;
15793     };
15794   },
15795   'unary-': function(argument, context) {
15796     return function(scope, locals, assign, inputs) {
15797       var arg = argument(scope, locals, assign, inputs);
15798       if (isDefined(arg)) {
15799         arg = -arg;
15800       } else {
15801         arg = 0;
15802       }
15803       return context ? {value: arg} : arg;
15804     };
15805   },
15806   'unary!': function(argument, context) {
15807     return function(scope, locals, assign, inputs) {
15808       var arg = !argument(scope, locals, assign, inputs);
15809       return context ? {value: arg} : arg;
15810     };
15811   },
15812   'binary+': function(left, right, context) {
15813     return function(scope, locals, assign, inputs) {
15814       var lhs = left(scope, locals, assign, inputs);
15815       var rhs = right(scope, locals, assign, inputs);
15816       var arg = plusFn(lhs, rhs);
15817       return context ? {value: arg} : arg;
15818     };
15819   },
15820   'binary-': function(left, right, context) {
15821     return function(scope, locals, assign, inputs) {
15822       var lhs = left(scope, locals, assign, inputs);
15823       var rhs = right(scope, locals, assign, inputs);
15824       var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
15825       return context ? {value: arg} : arg;
15826     };
15827   },
15828   'binary*': function(left, right, context) {
15829     return function(scope, locals, assign, inputs) {
15830       var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
15831       return context ? {value: arg} : arg;
15832     };
15833   },
15834   'binary/': function(left, right, context) {
15835     return function(scope, locals, assign, inputs) {
15836       var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
15837       return context ? {value: arg} : arg;
15838     };
15839   },
15840   'binary%': function(left, right, context) {
15841     return function(scope, locals, assign, inputs) {
15842       var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
15843       return context ? {value: arg} : arg;
15844     };
15845   },
15846   'binary===': function(left, right, context) {
15847     return function(scope, locals, assign, inputs) {
15848       var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
15849       return context ? {value: arg} : arg;
15850     };
15851   },
15852   'binary!==': function(left, right, context) {
15853     return function(scope, locals, assign, inputs) {
15854       var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
15855       return context ? {value: arg} : arg;
15856     };
15857   },
15858   'binary==': function(left, right, context) {
15859     return function(scope, locals, assign, inputs) {
15860       // eslint-disable-next-line eqeqeq
15861       var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
15862       return context ? {value: arg} : arg;
15863     };
15864   },
15865   'binary!=': function(left, right, context) {
15866     return function(scope, locals, assign, inputs) {
15867       // eslint-disable-next-line eqeqeq
15868       var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
15869       return context ? {value: arg} : arg;
15870     };
15871   },
15872   'binary<': function(left, right, context) {
15873     return function(scope, locals, assign, inputs) {
15874       var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
15875       return context ? {value: arg} : arg;
15876     };
15877   },
15878   'binary>': function(left, right, context) {
15879     return function(scope, locals, assign, inputs) {
15880       var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
15881       return context ? {value: arg} : arg;
15882     };
15883   },
15884   'binary<=': function(left, right, context) {
15885     return function(scope, locals, assign, inputs) {
15886       var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
15887       return context ? {value: arg} : arg;
15888     };
15889   },
15890   'binary>=': function(left, right, context) {
15891     return function(scope, locals, assign, inputs) {
15892       var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
15893       return context ? {value: arg} : arg;
15894     };
15895   },
15896   'binary&&': function(left, right, context) {
15897     return function(scope, locals, assign, inputs) {
15898       var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
15899       return context ? {value: arg} : arg;
15900     };
15901   },
15902   'binary||': function(left, right, context) {
15903     return function(scope, locals, assign, inputs) {
15904       var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
15905       return context ? {value: arg} : arg;
15906     };
15907   },
15908   'ternary?:': function(test, alternate, consequent, context) {
15909     return function(scope, locals, assign, inputs) {
15910       var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
15911       return context ? {value: arg} : arg;
15912     };
15913   },
15914   value: function(value, context) {
15915     return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
15916   },
15917   identifier: function(name, expensiveChecks, context, create, expression) {
15918     return function(scope, locals, assign, inputs) {
15919       var base = locals && (name in locals) ? locals : scope;
15920       if (create && create !== 1 && base && !(base[name])) {
15921         base[name] = {};
15922       }
15923       var value = base ? base[name] : undefined;
15924       if (expensiveChecks) {
15925         ensureSafeObject(value, expression);
15926       }
15927       if (context) {
15928         return {context: base, name: name, value: value};
15929       } else {
15930         return value;
15931       }
15932     };
15933   },
15934   computedMember: function(left, right, context, create, expression) {
15935     return function(scope, locals, assign, inputs) {
15936       var lhs = left(scope, locals, assign, inputs);
15937       var rhs;
15938       var value;
15939       if (lhs != null) {
15940         rhs = right(scope, locals, assign, inputs);
15941         rhs = getStringValue(rhs);
15942         ensureSafeMemberName(rhs, expression);
15943         if (create && create !== 1) {
15944           ensureSafeAssignContext(lhs);
15945           if (lhs && !(lhs[rhs])) {
15946             lhs[rhs] = {};
15947           }
15948         }
15949         value = lhs[rhs];
15950         ensureSafeObject(value, expression);
15951       }
15952       if (context) {
15953         return {context: lhs, name: rhs, value: value};
15954       } else {
15955         return value;
15956       }
15957     };
15958   },
15959   nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
15960     return function(scope, locals, assign, inputs) {
15961       var lhs = left(scope, locals, assign, inputs);
15962       if (create && create !== 1) {
15963         ensureSafeAssignContext(lhs);
15964         if (lhs && !(lhs[right])) {
15965           lhs[right] = {};
15966         }
15967       }
15968       var value = lhs != null ? lhs[right] : undefined;
15969       if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
15970         ensureSafeObject(value, expression);
15971       }
15972       if (context) {
15973         return {context: lhs, name: right, value: value};
15974       } else {
15975         return value;
15976       }
15977     };
15978   },
15979   inputs: function(input, watchId) {
15980     return function(scope, value, locals, inputs) {
15981       if (inputs) return inputs[watchId];
15982       return input(scope, value, locals);
15983     };
15984   }
15985 };
15986
15987 /**
15988  * @constructor
15989  */
15990 var Parser = function Parser(lexer, $filter, options) {
15991   this.lexer = lexer;
15992   this.$filter = $filter;
15993   this.options = options;
15994   this.ast = new AST(lexer, options);
15995   this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
15996                                    new ASTCompiler(this.ast, $filter);
15997 };
15998
15999 Parser.prototype = {
16000   constructor: Parser,
16001
16002   parse: function(text) {
16003     return this.astCompiler.compile(text, this.options.expensiveChecks);
16004   }
16005 };
16006
16007 function isPossiblyDangerousMemberName(name) {
16008   return name === 'constructor';
16009 }
16010
16011 function getValueOf(value) {
16012   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
16013 }
16014
16015 ///////////////////////////////////
16016
16017 /**
16018  * @ngdoc service
16019  * @name $parse
16020  * @kind function
16021  *
16022  * @description
16023  *
16024  * Converts Angular {@link guide/expression expression} into a function.
16025  *
16026  * ```js
16027  *   var getter = $parse('user.name');
16028  *   var setter = getter.assign;
16029  *   var context = {user:{name:'angular'}};
16030  *   var locals = {user:{name:'local'}};
16031  *
16032  *   expect(getter(context)).toEqual('angular');
16033  *   setter(context, 'newValue');
16034  *   expect(context.user.name).toEqual('newValue');
16035  *   expect(getter(context, locals)).toEqual('local');
16036  * ```
16037  *
16038  *
16039  * @param {string} expression String expression to compile.
16040  * @returns {function(context, locals)} a function which represents the compiled expression:
16041  *
16042  *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
16043  *      are evaluated against (typically a scope object).
16044  *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
16045  *      `context`.
16046  *
16047  *    The returned function also has the following properties:
16048  *      * `literal` â€“ `{boolean}` â€“ whether the expression's top-level node is a JavaScript
16049  *        literal.
16050  *      * `constant` â€“ `{boolean}` â€“ whether the expression is made entirely of JavaScript
16051  *        constant literals.
16052  *      * `assign` â€“ `{?function(context, value)}` â€“ if the expression is assignable, this will be
16053  *        set to a function to change its value on the given context.
16054  *
16055  */
16056
16057
16058 /**
16059  * @ngdoc provider
16060  * @name $parseProvider
16061  * @this
16062  *
16063  * @description
16064  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
16065  *  service.
16066  */
16067 function $ParseProvider() {
16068   var cacheDefault = createMap();
16069   var cacheExpensive = createMap();
16070   var literals = {
16071     'true': true,
16072     'false': false,
16073     'null': null,
16074     'undefined': undefined
16075   };
16076   var identStart, identContinue;
16077
16078   /**
16079    * @ngdoc method
16080    * @name $parseProvider#addLiteral
16081    * @description
16082    *
16083    * Configure $parse service to add literal values that will be present as literal at expressions.
16084    *
16085    * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
16086    * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
16087    *
16088    **/
16089   this.addLiteral = function(literalName, literalValue) {
16090     literals[literalName] = literalValue;
16091   };
16092
16093  /**
16094   * @ngdoc method
16095   * @name $parseProvider#setIdentifierFns
16096   *
16097   * @description
16098   *
16099   * Allows defining the set of characters that are allowed in Angular expressions. The function
16100   * `identifierStart` will get called to know if a given character is a valid character to be the
16101   * first character for an identifier. The function `identifierContinue` will get called to know if
16102   * a given character is a valid character to be a follow-up identifier character. The functions
16103   * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
16104   * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
16105   * mind that the `string` parameter can be two characters long depending on the character
16106   * representation. It is expected for the function to return `true` or `false`, whether that
16107   * character is allowed or not.
16108   *
16109   * Since this function will be called extensively, keep the implementation of these functions fast,
16110   * as the performance of these functions have a direct impact on the expressions parsing speed.
16111   *
16112   * @param {function=} identifierStart The function that will decide whether the given character is
16113   *   a valid identifier start character.
16114   * @param {function=} identifierContinue The function that will decide whether the given character is
16115   *   a valid identifier continue character.
16116   */
16117   this.setIdentifierFns = function(identifierStart, identifierContinue) {
16118     identStart = identifierStart;
16119     identContinue = identifierContinue;
16120     return this;
16121   };
16122
16123   this.$get = ['$filter', function($filter) {
16124     var noUnsafeEval = csp().noUnsafeEval;
16125     var $parseOptions = {
16126           csp: noUnsafeEval,
16127           expensiveChecks: false,
16128           literals: copy(literals),
16129           isIdentifierStart: isFunction(identStart) && identStart,
16130           isIdentifierContinue: isFunction(identContinue) && identContinue
16131         },
16132         $parseOptionsExpensive = {
16133           csp: noUnsafeEval,
16134           expensiveChecks: true,
16135           literals: copy(literals),
16136           isIdentifierStart: isFunction(identStart) && identStart,
16137           isIdentifierContinue: isFunction(identContinue) && identContinue
16138         };
16139     var runningChecksEnabled = false;
16140
16141     $parse.$$runningExpensiveChecks = function() {
16142       return runningChecksEnabled;
16143     };
16144
16145     return $parse;
16146
16147     function $parse(exp, interceptorFn, expensiveChecks) {
16148       var parsedExpression, oneTime, cacheKey;
16149
16150       expensiveChecks = expensiveChecks || runningChecksEnabled;
16151
16152       switch (typeof exp) {
16153         case 'string':
16154           exp = exp.trim();
16155           cacheKey = exp;
16156
16157           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
16158           parsedExpression = cache[cacheKey];
16159
16160           if (!parsedExpression) {
16161             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
16162               oneTime = true;
16163               exp = exp.substring(2);
16164             }
16165             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
16166             var lexer = new Lexer(parseOptions);
16167             var parser = new Parser(lexer, $filter, parseOptions);
16168             parsedExpression = parser.parse(exp);
16169             if (parsedExpression.constant) {
16170               parsedExpression.$$watchDelegate = constantWatchDelegate;
16171             } else if (oneTime) {
16172               parsedExpression.$$watchDelegate = parsedExpression.literal ?
16173                   oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
16174             } else if (parsedExpression.inputs) {
16175               parsedExpression.$$watchDelegate = inputsWatchDelegate;
16176             }
16177             if (expensiveChecks) {
16178               parsedExpression = expensiveChecksInterceptor(parsedExpression);
16179             }
16180             cache[cacheKey] = parsedExpression;
16181           }
16182           return addInterceptor(parsedExpression, interceptorFn);
16183
16184         case 'function':
16185           return addInterceptor(exp, interceptorFn);
16186
16187         default:
16188           return addInterceptor(noop, interceptorFn);
16189       }
16190     }
16191
16192     function expensiveChecksInterceptor(fn) {
16193       if (!fn) return fn;
16194       expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
16195       expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
16196       expensiveCheckFn.constant = fn.constant;
16197       expensiveCheckFn.literal = fn.literal;
16198       for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
16199         fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
16200       }
16201       expensiveCheckFn.inputs = fn.inputs;
16202
16203       return expensiveCheckFn;
16204
16205       function expensiveCheckFn(scope, locals, assign, inputs) {
16206         var expensiveCheckOldValue = runningChecksEnabled;
16207         runningChecksEnabled = true;
16208         try {
16209           return fn(scope, locals, assign, inputs);
16210         } finally {
16211           runningChecksEnabled = expensiveCheckOldValue;
16212         }
16213       }
16214     }
16215
16216     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
16217
16218       if (newValue == null || oldValueOfValue == null) { // null/undefined
16219         return newValue === oldValueOfValue;
16220       }
16221
16222       if (typeof newValue === 'object') {
16223
16224         // attempt to convert the value to a primitive type
16225         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
16226         //             be cheaply dirty-checked
16227         newValue = getValueOf(newValue);
16228
16229         if (typeof newValue === 'object') {
16230           // objects/arrays are not supported - deep-watching them would be too expensive
16231           return false;
16232         }
16233
16234         // fall-through to the primitive equality check
16235       }
16236
16237       //Primitive or NaN
16238       // eslint-disable-next-line no-self-compare
16239       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
16240     }
16241
16242     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
16243       var inputExpressions = parsedExpression.inputs;
16244       var lastResult;
16245
16246       if (inputExpressions.length === 1) {
16247         var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
16248         inputExpressions = inputExpressions[0];
16249         return scope.$watch(function expressionInputWatch(scope) {
16250           var newInputValue = inputExpressions(scope);
16251           if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
16252             lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
16253             oldInputValueOf = newInputValue && getValueOf(newInputValue);
16254           }
16255           return lastResult;
16256         }, listener, objectEquality, prettyPrintExpression);
16257       }
16258
16259       var oldInputValueOfValues = [];
16260       var oldInputValues = [];
16261       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
16262         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
16263         oldInputValues[i] = null;
16264       }
16265
16266       return scope.$watch(function expressionInputsWatch(scope) {
16267         var changed = false;
16268
16269         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
16270           var newInputValue = inputExpressions[i](scope);
16271           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
16272             oldInputValues[i] = newInputValue;
16273             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
16274           }
16275         }
16276
16277         if (changed) {
16278           lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
16279         }
16280
16281         return lastResult;
16282       }, listener, objectEquality, prettyPrintExpression);
16283     }
16284
16285     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
16286       var unwatch, lastValue;
16287       unwatch = scope.$watch(function oneTimeWatch(scope) {
16288         return parsedExpression(scope);
16289       }, /** @this */ function oneTimeListener(value, old, scope) {
16290         lastValue = value;
16291         if (isFunction(listener)) {
16292           listener.apply(this, arguments);
16293         }
16294         if (isDefined(value)) {
16295           scope.$$postDigest(function() {
16296             if (isDefined(lastValue)) {
16297               unwatch();
16298             }
16299           });
16300         }
16301       }, objectEquality);
16302       return unwatch;
16303     }
16304
16305     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
16306       var unwatch, lastValue;
16307       unwatch = scope.$watch(function oneTimeWatch(scope) {
16308         return parsedExpression(scope);
16309       }, /** @this */ function oneTimeListener(value, old, scope) {
16310         lastValue = value;
16311         if (isFunction(listener)) {
16312           listener.call(this, value, old, scope);
16313         }
16314         if (isAllDefined(value)) {
16315           scope.$$postDigest(function() {
16316             if (isAllDefined(lastValue)) unwatch();
16317           });
16318         }
16319       }, objectEquality);
16320
16321       return unwatch;
16322
16323       function isAllDefined(value) {
16324         var allDefined = true;
16325         forEach(value, function(val) {
16326           if (!isDefined(val)) allDefined = false;
16327         });
16328         return allDefined;
16329       }
16330     }
16331
16332     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
16333       var unwatch = scope.$watch(function constantWatch(scope) {
16334         unwatch();
16335         return parsedExpression(scope);
16336       }, listener, objectEquality);
16337       return unwatch;
16338     }
16339
16340     function addInterceptor(parsedExpression, interceptorFn) {
16341       if (!interceptorFn) return parsedExpression;
16342       var watchDelegate = parsedExpression.$$watchDelegate;
16343       var useInputs = false;
16344
16345       var regularWatch =
16346           watchDelegate !== oneTimeLiteralWatchDelegate &&
16347           watchDelegate !== oneTimeWatchDelegate;
16348
16349       var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
16350         var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
16351         return interceptorFn(value, scope, locals);
16352       } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
16353         var value = parsedExpression(scope, locals, assign, inputs);
16354         var result = interceptorFn(value, scope, locals);
16355         // we only return the interceptor's result if the
16356         // initial value is defined (for bind-once)
16357         return isDefined(value) ? result : value;
16358       };
16359
16360       // Propagate $$watchDelegates other then inputsWatchDelegate
16361       if (parsedExpression.$$watchDelegate &&
16362           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
16363         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
16364       } else if (!interceptorFn.$stateful) {
16365         // If there is an interceptor, but no watchDelegate then treat the interceptor like
16366         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
16367         fn.$$watchDelegate = inputsWatchDelegate;
16368         useInputs = !parsedExpression.inputs;
16369         fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
16370       }
16371
16372       return fn;
16373     }
16374   }];
16375 }
16376
16377 /**
16378  * @ngdoc service
16379  * @name $q
16380  * @requires $rootScope
16381  * @this
16382  *
16383  * @description
16384  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
16385  * when they are done processing.
16386  *
16387  * This is an implementation of promises/deferred objects inspired by
16388  * [Kris Kowal's Q](https://github.com/kriskowal/q).
16389  *
16390  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
16391  * implementations, and the other which resembles ES6 (ES2015) promises to some degree.
16392  *
16393  * # $q constructor
16394  *
16395  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
16396  * function as the first argument. This is similar to the native Promise implementation from ES6,
16397  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
16398  *
16399  * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
16400  * available yet.
16401  *
16402  * It can be used like so:
16403  *
16404  * ```js
16405  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
16406  *   // are available in the current lexical scope (they could have been injected or passed in).
16407  *
16408  *   function asyncGreet(name) {
16409  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
16410  *     return $q(function(resolve, reject) {
16411  *       setTimeout(function() {
16412  *         if (okToGreet(name)) {
16413  *           resolve('Hello, ' + name + '!');
16414  *         } else {
16415  *           reject('Greeting ' + name + ' is not allowed.');
16416  *         }
16417  *       }, 1000);
16418  *     });
16419  *   }
16420  *
16421  *   var promise = asyncGreet('Robin Hood');
16422  *   promise.then(function(greeting) {
16423  *     alert('Success: ' + greeting);
16424  *   }, function(reason) {
16425  *     alert('Failed: ' + reason);
16426  *   });
16427  * ```
16428  *
16429  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
16430  *
16431  * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
16432  *
16433  * However, the more traditional CommonJS-style usage is still available, and documented below.
16434  *
16435  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
16436  * interface for interacting with an object that represents the result of an action that is
16437  * performed asynchronously, and may or may not be finished at any given point in time.
16438  *
16439  * From the perspective of dealing with error handling, deferred and promise APIs are to
16440  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
16441  *
16442  * ```js
16443  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
16444  *   // are available in the current lexical scope (they could have been injected or passed in).
16445  *
16446  *   function asyncGreet(name) {
16447  *     var deferred = $q.defer();
16448  *
16449  *     setTimeout(function() {
16450  *       deferred.notify('About to greet ' + name + '.');
16451  *
16452  *       if (okToGreet(name)) {
16453  *         deferred.resolve('Hello, ' + name + '!');
16454  *       } else {
16455  *         deferred.reject('Greeting ' + name + ' is not allowed.');
16456  *       }
16457  *     }, 1000);
16458  *
16459  *     return deferred.promise;
16460  *   }
16461  *
16462  *   var promise = asyncGreet('Robin Hood');
16463  *   promise.then(function(greeting) {
16464  *     alert('Success: ' + greeting);
16465  *   }, function(reason) {
16466  *     alert('Failed: ' + reason);
16467  *   }, function(update) {
16468  *     alert('Got notification: ' + update);
16469  *   });
16470  * ```
16471  *
16472  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
16473  * comes in the way of guarantees that promise and deferred APIs make, see
16474  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
16475  *
16476  * Additionally the promise api allows for composition that is very hard to do with the
16477  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
16478  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
16479  * section on serial or parallel joining of promises.
16480  *
16481  * # The Deferred API
16482  *
16483  * A new instance of deferred is constructed by calling `$q.defer()`.
16484  *
16485  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
16486  * that can be used for signaling the successful or unsuccessful completion, as well as the status
16487  * of the task.
16488  *
16489  * **Methods**
16490  *
16491  * - `resolve(value)` â€“ resolves the derived promise with the `value`. If the value is a rejection
16492  *   constructed via `$q.reject`, the promise will be rejected instead.
16493  * - `reject(reason)` â€“ rejects the derived promise with the `reason`. This is equivalent to
16494  *   resolving it with a rejection constructed via `$q.reject`.
16495  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
16496  *   multiple times before the promise is either resolved or rejected.
16497  *
16498  * **Properties**
16499  *
16500  * - promise â€“ `{Promise}` â€“ promise object associated with this deferred.
16501  *
16502  *
16503  * # The Promise API
16504  *
16505  * A new promise instance is created when a deferred instance is created and can be retrieved by
16506  * calling `deferred.promise`.
16507  *
16508  * The purpose of the promise object is to allow for interested parties to get access to the result
16509  * of the deferred task when it completes.
16510  *
16511  * **Methods**
16512  *
16513  * - `then(successCallback, [errorCallback], [notifyCallback])` â€“ regardless of when the promise was or
16514  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
16515  *   as soon as the result is available. The callbacks are called with a single argument: the result
16516  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
16517  *   provide a progress indication, before the promise is resolved or rejected.
16518  *
16519  *   This method *returns a new promise* which is resolved or rejected via the return value of the
16520  *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
16521  *   with the value which is resolved in that promise using
16522  *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
16523  *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
16524  *   resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
16525  *   arguments are optional.
16526  *
16527  * - `catch(errorCallback)` â€“ shorthand for `promise.then(null, errorCallback)`
16528  *
16529  * - `finally(callback, notifyCallback)` â€“ allows you to observe either the fulfillment or rejection of a promise,
16530  *   but to do so without modifying the final value. This is useful to release resources or do some
16531  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
16532  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
16533  *   more information.
16534  *
16535  * # Chaining promises
16536  *
16537  * Because calling the `then` method of a promise returns a new derived promise, it is easily
16538  * possible to create a chain of promises:
16539  *
16540  * ```js
16541  *   promiseB = promiseA.then(function(result) {
16542  *     return result + 1;
16543  *   });
16544  *
16545  *   // promiseB will be resolved immediately after promiseA is resolved and its value
16546  *   // will be the result of promiseA incremented by 1
16547  * ```
16548  *
16549  * It is possible to create chains of any length and since a promise can be resolved with another
16550  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
16551  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
16552  * $http's response interceptors.
16553  *
16554  *
16555  * # Differences between Kris Kowal's Q and $q
16556  *
16557  *  There are two main differences:
16558  *
16559  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
16560  *   mechanism in angular, which means faster propagation of resolution or rejection into your
16561  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
16562  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
16563  *   all the important functionality needed for common async tasks.
16564  *
16565  * # Testing
16566  *
16567  *  ```js
16568  *    it('should simulate promise', inject(function($q, $rootScope) {
16569  *      var deferred = $q.defer();
16570  *      var promise = deferred.promise;
16571  *      var resolvedValue;
16572  *
16573  *      promise.then(function(value) { resolvedValue = value; });
16574  *      expect(resolvedValue).toBeUndefined();
16575  *
16576  *      // Simulate resolving of promise
16577  *      deferred.resolve(123);
16578  *      // Note that the 'then' function does not get called synchronously.
16579  *      // This is because we want the promise API to always be async, whether or not
16580  *      // it got called synchronously or asynchronously.
16581  *      expect(resolvedValue).toBeUndefined();
16582  *
16583  *      // Propagate promise resolution to 'then' functions using $apply().
16584  *      $rootScope.$apply();
16585  *      expect(resolvedValue).toEqual(123);
16586  *    }));
16587  *  ```
16588  *
16589  * @param {function(function, function)} resolver Function which is responsible for resolving or
16590  *   rejecting the newly created promise. The first parameter is a function which resolves the
16591  *   promise, the second parameter is a function which rejects the promise.
16592  *
16593  * @returns {Promise} The newly created promise.
16594  */
16595 function $QProvider() {
16596
16597   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
16598     return qFactory(function(callback) {
16599       $rootScope.$evalAsync(callback);
16600     }, $exceptionHandler);
16601   }];
16602 }
16603
16604 /** @this */
16605 function $$QProvider() {
16606   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
16607     return qFactory(function(callback) {
16608       $browser.defer(callback);
16609     }, $exceptionHandler);
16610   }];
16611 }
16612
16613 /**
16614  * Constructs a promise manager.
16615  *
16616  * @param {function(function)} nextTick Function for executing functions in the next turn.
16617  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
16618  *     debugging purposes.
16619  * @returns {object} Promise manager.
16620  */
16621 function qFactory(nextTick, exceptionHandler) {
16622   var $qMinErr = minErr('$q', TypeError);
16623
16624   /**
16625    * @ngdoc method
16626    * @name ng.$q#defer
16627    * @kind function
16628    *
16629    * @description
16630    * Creates a `Deferred` object which represents a task which will finish in the future.
16631    *
16632    * @returns {Deferred} Returns a new instance of deferred.
16633    */
16634   function defer() {
16635     var d = new Deferred();
16636     //Necessary to support unbound execution :/
16637     d.resolve = simpleBind(d, d.resolve);
16638     d.reject = simpleBind(d, d.reject);
16639     d.notify = simpleBind(d, d.notify);
16640     return d;
16641   }
16642
16643   function Promise() {
16644     this.$$state = { status: 0 };
16645   }
16646
16647   extend(Promise.prototype, {
16648     then: function(onFulfilled, onRejected, progressBack) {
16649       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
16650         return this;
16651       }
16652       var result = new Deferred();
16653
16654       this.$$state.pending = this.$$state.pending || [];
16655       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
16656       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
16657
16658       return result.promise;
16659     },
16660
16661     'catch': function(callback) {
16662       return this.then(null, callback);
16663     },
16664
16665     'finally': function(callback, progressBack) {
16666       return this.then(function(value) {
16667         return handleCallback(value, resolve, callback);
16668       }, function(error) {
16669         return handleCallback(error, reject, callback);
16670       }, progressBack);
16671     }
16672   });
16673
16674   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
16675   function simpleBind(context, fn) {
16676     return function(value) {
16677       fn.call(context, value);
16678     };
16679   }
16680
16681   function processQueue(state) {
16682     var fn, deferred, pending;
16683
16684     pending = state.pending;
16685     state.processScheduled = false;
16686     state.pending = undefined;
16687     for (var i = 0, ii = pending.length; i < ii; ++i) {
16688       deferred = pending[i][0];
16689       fn = pending[i][state.status];
16690       try {
16691         if (isFunction(fn)) {
16692           deferred.resolve(fn(state.value));
16693         } else if (state.status === 1) {
16694           deferred.resolve(state.value);
16695         } else {
16696           deferred.reject(state.value);
16697         }
16698       } catch (e) {
16699         deferred.reject(e);
16700         exceptionHandler(e);
16701       }
16702     }
16703   }
16704
16705   function scheduleProcessQueue(state) {
16706     if (state.processScheduled || !state.pending) return;
16707     state.processScheduled = true;
16708     nextTick(function() { processQueue(state); });
16709   }
16710
16711   function Deferred() {
16712     this.promise = new Promise();
16713   }
16714
16715   extend(Deferred.prototype, {
16716     resolve: function(val) {
16717       if (this.promise.$$state.status) return;
16718       if (val === this.promise) {
16719         this.$$reject($qMinErr(
16720           'qcycle',
16721           'Expected promise to be resolved with value other than itself \'{0}\'',
16722           val));
16723       } else {
16724         this.$$resolve(val);
16725       }
16726
16727     },
16728
16729     $$resolve: function(val) {
16730       var then;
16731       var that = this;
16732       var done = false;
16733       try {
16734         if ((isObject(val) || isFunction(val))) then = val && val.then;
16735         if (isFunction(then)) {
16736           this.promise.$$state.status = -1;
16737           then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
16738         } else {
16739           this.promise.$$state.value = val;
16740           this.promise.$$state.status = 1;
16741           scheduleProcessQueue(this.promise.$$state);
16742         }
16743       } catch (e) {
16744         rejectPromise(e);
16745         exceptionHandler(e);
16746       }
16747
16748       function resolvePromise(val) {
16749         if (done) return;
16750         done = true;
16751         that.$$resolve(val);
16752       }
16753       function rejectPromise(val) {
16754         if (done) return;
16755         done = true;
16756         that.$$reject(val);
16757       }
16758     },
16759
16760     reject: function(reason) {
16761       if (this.promise.$$state.status) return;
16762       this.$$reject(reason);
16763     },
16764
16765     $$reject: function(reason) {
16766       this.promise.$$state.value = reason;
16767       this.promise.$$state.status = 2;
16768       scheduleProcessQueue(this.promise.$$state);
16769     },
16770
16771     notify: function(progress) {
16772       var callbacks = this.promise.$$state.pending;
16773
16774       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
16775         nextTick(function() {
16776           var callback, result;
16777           for (var i = 0, ii = callbacks.length; i < ii; i++) {
16778             result = callbacks[i][0];
16779             callback = callbacks[i][3];
16780             try {
16781               result.notify(isFunction(callback) ? callback(progress) : progress);
16782             } catch (e) {
16783               exceptionHandler(e);
16784             }
16785           }
16786         });
16787       }
16788     }
16789   });
16790
16791   /**
16792    * @ngdoc method
16793    * @name $q#reject
16794    * @kind function
16795    *
16796    * @description
16797    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
16798    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
16799    * a promise chain, you don't need to worry about it.
16800    *
16801    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
16802    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
16803    * a promise error callback and you want to forward the error to the promise derived from the
16804    * current promise, you have to "rethrow" the error by returning a rejection constructed via
16805    * `reject`.
16806    *
16807    * ```js
16808    *   promiseB = promiseA.then(function(result) {
16809    *     // success: do something and resolve promiseB
16810    *     //          with the old or a new result
16811    *     return result;
16812    *   }, function(reason) {
16813    *     // error: handle the error if possible and
16814    *     //        resolve promiseB with newPromiseOrValue,
16815    *     //        otherwise forward the rejection to promiseB
16816    *     if (canHandle(reason)) {
16817    *      // handle the error and recover
16818    *      return newPromiseOrValue;
16819    *     }
16820    *     return $q.reject(reason);
16821    *   });
16822    * ```
16823    *
16824    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
16825    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
16826    */
16827   function reject(reason) {
16828     var result = new Deferred();
16829     result.reject(reason);
16830     return result.promise;
16831   }
16832
16833   function handleCallback(value, resolver, callback) {
16834     var callbackOutput = null;
16835     try {
16836       if (isFunction(callback)) callbackOutput = callback();
16837     } catch (e) {
16838       return reject(e);
16839     }
16840     if (isPromiseLike(callbackOutput)) {
16841       return callbackOutput.then(function() {
16842         return resolver(value);
16843       }, reject);
16844     } else {
16845       return resolver(value);
16846     }
16847   }
16848
16849   /**
16850    * @ngdoc method
16851    * @name $q#when
16852    * @kind function
16853    *
16854    * @description
16855    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
16856    * This is useful when you are dealing with an object that might or might not be a promise, or if
16857    * the promise comes from a source that can't be trusted.
16858    *
16859    * @param {*} value Value or a promise
16860    * @param {Function=} successCallback
16861    * @param {Function=} errorCallback
16862    * @param {Function=} progressCallback
16863    * @returns {Promise} Returns a promise of the passed value or promise
16864    */
16865
16866
16867   function when(value, callback, errback, progressBack) {
16868     var result = new Deferred();
16869     result.resolve(value);
16870     return result.promise.then(callback, errback, progressBack);
16871   }
16872
16873   /**
16874    * @ngdoc method
16875    * @name $q#resolve
16876    * @kind function
16877    *
16878    * @description
16879    * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
16880    *
16881    * @param {*} value Value or a promise
16882    * @param {Function=} successCallback
16883    * @param {Function=} errorCallback
16884    * @param {Function=} progressCallback
16885    * @returns {Promise} Returns a promise of the passed value or promise
16886    */
16887   var resolve = when;
16888
16889   /**
16890    * @ngdoc method
16891    * @name $q#all
16892    * @kind function
16893    *
16894    * @description
16895    * Combines multiple promises into a single promise that is resolved when all of the input
16896    * promises are resolved.
16897    *
16898    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
16899    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
16900    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
16901    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
16902    *   with the same rejection value.
16903    */
16904
16905   function all(promises) {
16906     var deferred = new Deferred(),
16907         counter = 0,
16908         results = isArray(promises) ? [] : {};
16909
16910     forEach(promises, function(promise, key) {
16911       counter++;
16912       when(promise).then(function(value) {
16913         results[key] = value;
16914         if (!(--counter)) deferred.resolve(results);
16915       }, function(reason) {
16916         deferred.reject(reason);
16917       });
16918     });
16919
16920     if (counter === 0) {
16921       deferred.resolve(results);
16922     }
16923
16924     return deferred.promise;
16925   }
16926
16927   /**
16928    * @ngdoc method
16929    * @name $q#race
16930    * @kind function
16931    *
16932    * @description
16933    * Returns a promise that resolves or rejects as soon as one of those promises
16934    * resolves or rejects, with the value or reason from that promise.
16935    *
16936    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
16937    * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
16938    * resolves or rejects, with the value or reason from that promise.
16939    */
16940
16941   function race(promises) {
16942     var deferred = defer();
16943
16944     forEach(promises, function(promise) {
16945       when(promise).then(deferred.resolve, deferred.reject);
16946     });
16947
16948     return deferred.promise;
16949   }
16950
16951   function $Q(resolver) {
16952     if (!isFunction(resolver)) {
16953       throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver);
16954     }
16955
16956     var deferred = new Deferred();
16957
16958     function resolveFn(value) {
16959       deferred.resolve(value);
16960     }
16961
16962     function rejectFn(reason) {
16963       deferred.reject(reason);
16964     }
16965
16966     resolver(resolveFn, rejectFn);
16967
16968     return deferred.promise;
16969   }
16970
16971   // Let's make the instanceof operator work for promises, so that
16972   // `new $q(fn) instanceof $q` would evaluate to true.
16973   $Q.prototype = Promise.prototype;
16974
16975   $Q.defer = defer;
16976   $Q.reject = reject;
16977   $Q.when = when;
16978   $Q.resolve = resolve;
16979   $Q.all = all;
16980   $Q.race = race;
16981
16982   return $Q;
16983 }
16984
16985 /** @this */
16986 function $$RAFProvider() { //rAF
16987   this.$get = ['$window', '$timeout', function($window, $timeout) {
16988     var requestAnimationFrame = $window.requestAnimationFrame ||
16989                                 $window.webkitRequestAnimationFrame;
16990
16991     var cancelAnimationFrame = $window.cancelAnimationFrame ||
16992                                $window.webkitCancelAnimationFrame ||
16993                                $window.webkitCancelRequestAnimationFrame;
16994
16995     var rafSupported = !!requestAnimationFrame;
16996     var raf = rafSupported
16997       ? function(fn) {
16998           var id = requestAnimationFrame(fn);
16999           return function() {
17000             cancelAnimationFrame(id);
17001           };
17002         }
17003       : function(fn) {
17004           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
17005           return function() {
17006             $timeout.cancel(timer);
17007           };
17008         };
17009
17010     raf.supported = rafSupported;
17011
17012     return raf;
17013   }];
17014 }
17015
17016 /**
17017  * DESIGN NOTES
17018  *
17019  * The design decisions behind the scope are heavily favored for speed and memory consumption.
17020  *
17021  * The typical use of scope is to watch the expressions, which most of the time return the same
17022  * value as last time so we optimize the operation.
17023  *
17024  * Closures construction is expensive in terms of speed as well as memory:
17025  *   - No closures, instead use prototypical inheritance for API
17026  *   - Internal state needs to be stored on scope directly, which means that private state is
17027  *     exposed as $$____ properties
17028  *
17029  * Loop operations are optimized by using while(count--) { ... }
17030  *   - This means that in order to keep the same order of execution as addition we have to add
17031  *     items to the array at the beginning (unshift) instead of at the end (push)
17032  *
17033  * Child scopes are created and removed often
17034  *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
17035  *
17036  * There are fewer watches than observers. This is why you don't want the observer to be implemented
17037  * in the same way as watch. Watch requires return of the initialization function which is expensive
17038  * to construct.
17039  */
17040
17041
17042 /**
17043  * @ngdoc provider
17044  * @name $rootScopeProvider
17045  * @description
17046  *
17047  * Provider for the $rootScope service.
17048  */
17049
17050 /**
17051  * @ngdoc method
17052  * @name $rootScopeProvider#digestTtl
17053  * @description
17054  *
17055  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
17056  * assuming that the model is unstable.
17057  *
17058  * The current default is 10 iterations.
17059  *
17060  * In complex applications it's possible that the dependencies between `$watch`s will result in
17061  * several digest iterations. However if an application needs more than the default 10 digest
17062  * iterations for its model to stabilize then you should investigate what is causing the model to
17063  * continuously change during the digest.
17064  *
17065  * Increasing the TTL could have performance implications, so you should not change it without
17066  * proper justification.
17067  *
17068  * @param {number} limit The number of digest iterations.
17069  */
17070
17071
17072 /**
17073  * @ngdoc service
17074  * @name $rootScope
17075  * @this
17076  *
17077  * @description
17078  *
17079  * Every application has a single root {@link ng.$rootScope.Scope scope}.
17080  * All other scopes are descendant scopes of the root scope. Scopes provide separation
17081  * between the model and the view, via a mechanism for watching the model for changes.
17082  * They also provide event emission/broadcast and subscription facility. See the
17083  * {@link guide/scope developer guide on scopes}.
17084  */
17085 function $RootScopeProvider() {
17086   var TTL = 10;
17087   var $rootScopeMinErr = minErr('$rootScope');
17088   var lastDirtyWatch = null;
17089   var applyAsyncId = null;
17090
17091   this.digestTtl = function(value) {
17092     if (arguments.length) {
17093       TTL = value;
17094     }
17095     return TTL;
17096   };
17097
17098   function createChildScopeClass(parent) {
17099     function ChildScope() {
17100       this.$$watchers = this.$$nextSibling =
17101           this.$$childHead = this.$$childTail = null;
17102       this.$$listeners = {};
17103       this.$$listenerCount = {};
17104       this.$$watchersCount = 0;
17105       this.$id = nextUid();
17106       this.$$ChildScope = null;
17107     }
17108     ChildScope.prototype = parent;
17109     return ChildScope;
17110   }
17111
17112   this.$get = ['$exceptionHandler', '$parse', '$browser',
17113       function($exceptionHandler, $parse, $browser) {
17114
17115     function destroyChildScope($event) {
17116         $event.currentScope.$$destroyed = true;
17117     }
17118
17119     function cleanUpScope($scope) {
17120
17121       if (msie === 9) {
17122         // There is a memory leak in IE9 if all child scopes are not disconnected
17123         // completely when a scope is destroyed. So this code will recurse up through
17124         // all this scopes children
17125         //
17126         // See issue https://github.com/angular/angular.js/issues/10706
17127         if ($scope.$$childHead) {
17128           cleanUpScope($scope.$$childHead);
17129         }
17130         if ($scope.$$nextSibling) {
17131           cleanUpScope($scope.$$nextSibling);
17132         }
17133       }
17134
17135       // The code below works around IE9 and V8's memory leaks
17136       //
17137       // See:
17138       // - https://code.google.com/p/v8/issues/detail?id=2073#c26
17139       // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
17140       // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
17141
17142       $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
17143           $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
17144     }
17145
17146     /**
17147      * @ngdoc type
17148      * @name $rootScope.Scope
17149      *
17150      * @description
17151      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
17152      * {@link auto.$injector $injector}. Child scopes are created using the
17153      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
17154      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
17155      * an in-depth introduction and usage examples.
17156      *
17157      *
17158      * # Inheritance
17159      * A scope can inherit from a parent scope, as in this example:
17160      * ```js
17161          var parent = $rootScope;
17162          var child = parent.$new();
17163
17164          parent.salutation = "Hello";
17165          expect(child.salutation).toEqual('Hello');
17166
17167          child.salutation = "Welcome";
17168          expect(child.salutation).toEqual('Welcome');
17169          expect(parent.salutation).toEqual('Hello');
17170      * ```
17171      *
17172      * When interacting with `Scope` in tests, additional helper methods are available on the
17173      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
17174      * details.
17175      *
17176      *
17177      * @param {Object.<string, function()>=} providers Map of service factory which need to be
17178      *                                       provided for the current scope. Defaults to {@link ng}.
17179      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
17180      *                              append/override services provided by `providers`. This is handy
17181      *                              when unit-testing and having the need to override a default
17182      *                              service.
17183      * @returns {Object} Newly created scope.
17184      *
17185      */
17186     function Scope() {
17187       this.$id = nextUid();
17188       this.$$phase = this.$parent = this.$$watchers =
17189                      this.$$nextSibling = this.$$prevSibling =
17190                      this.$$childHead = this.$$childTail = null;
17191       this.$root = this;
17192       this.$$destroyed = false;
17193       this.$$listeners = {};
17194       this.$$listenerCount = {};
17195       this.$$watchersCount = 0;
17196       this.$$isolateBindings = null;
17197     }
17198
17199     /**
17200      * @ngdoc property
17201      * @name $rootScope.Scope#$id
17202      *
17203      * @description
17204      * Unique scope ID (monotonically increasing) useful for debugging.
17205      */
17206
17207      /**
17208       * @ngdoc property
17209       * @name $rootScope.Scope#$parent
17210       *
17211       * @description
17212       * Reference to the parent scope.
17213       */
17214
17215       /**
17216        * @ngdoc property
17217        * @name $rootScope.Scope#$root
17218        *
17219        * @description
17220        * Reference to the root scope.
17221        */
17222
17223     Scope.prototype = {
17224       constructor: Scope,
17225       /**
17226        * @ngdoc method
17227        * @name $rootScope.Scope#$new
17228        * @kind function
17229        *
17230        * @description
17231        * Creates a new child {@link ng.$rootScope.Scope scope}.
17232        *
17233        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
17234        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
17235        *
17236        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
17237        * desired for the scope and its child scopes to be permanently detached from the parent and
17238        * thus stop participating in model change detection and listener notification by invoking.
17239        *
17240        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
17241        *         parent scope. The scope is isolated, as it can not see parent scope properties.
17242        *         When creating widgets, it is useful for the widget to not accidentally read parent
17243        *         state.
17244        *
17245        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
17246        *                              of the newly created scope. Defaults to `this` scope if not provided.
17247        *                              This is used when creating a transclude scope to correctly place it
17248        *                              in the scope hierarchy while maintaining the correct prototypical
17249        *                              inheritance.
17250        *
17251        * @returns {Object} The newly created child scope.
17252        *
17253        */
17254       $new: function(isolate, parent) {
17255         var child;
17256
17257         parent = parent || this;
17258
17259         if (isolate) {
17260           child = new Scope();
17261           child.$root = this.$root;
17262         } else {
17263           // Only create a child scope class if somebody asks for one,
17264           // but cache it to allow the VM to optimize lookups.
17265           if (!this.$$ChildScope) {
17266             this.$$ChildScope = createChildScopeClass(this);
17267           }
17268           child = new this.$$ChildScope();
17269         }
17270         child.$parent = parent;
17271         child.$$prevSibling = parent.$$childTail;
17272         if (parent.$$childHead) {
17273           parent.$$childTail.$$nextSibling = child;
17274           parent.$$childTail = child;
17275         } else {
17276           parent.$$childHead = parent.$$childTail = child;
17277         }
17278
17279         // When the new scope is not isolated or we inherit from `this`, and
17280         // the parent scope is destroyed, the property `$$destroyed` is inherited
17281         // prototypically. In all other cases, this property needs to be set
17282         // when the parent scope is destroyed.
17283         // The listener needs to be added after the parent is set
17284         if (isolate || parent !== this) child.$on('$destroy', destroyChildScope);
17285
17286         return child;
17287       },
17288
17289       /**
17290        * @ngdoc method
17291        * @name $rootScope.Scope#$watch
17292        * @kind function
17293        *
17294        * @description
17295        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
17296        *
17297        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
17298        *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
17299        *   its value when executed multiple times with the same input because it may be executed multiple
17300        *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
17301        *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).)
17302        * - The `listener` is called only when the value from the current `watchExpression` and the
17303        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
17304        *   see below). Inequality is determined according to reference inequality,
17305        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
17306        *    via the `!==` Javascript operator, unless `objectEquality == true`
17307        *   (see next point)
17308        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
17309        *   according to the {@link angular.equals} function. To save the value of the object for
17310        *   later comparison, the {@link angular.copy} function is used. This therefore means that
17311        *   watching complex objects will have adverse memory and performance implications.
17312        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
17313        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
17314        *   iteration limit is 10 to prevent an infinite loop deadlock.
17315        *
17316        *
17317        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
17318        * you can register a `watchExpression` function with no `listener`. (Be prepared for
17319        * multiple calls to your `watchExpression` because it will execute multiple times in a
17320        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
17321        *
17322        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
17323        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
17324        * watcher. In rare cases, this is undesirable because the listener is called when the result
17325        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
17326        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
17327        * listener was called due to initialization.
17328        *
17329        *
17330        *
17331        * # Example
17332        * ```js
17333            // let's assume that scope was dependency injected as the $rootScope
17334            var scope = $rootScope;
17335            scope.name = 'misko';
17336            scope.counter = 0;
17337
17338            expect(scope.counter).toEqual(0);
17339            scope.$watch('name', function(newValue, oldValue) {
17340              scope.counter = scope.counter + 1;
17341            });
17342            expect(scope.counter).toEqual(0);
17343
17344            scope.$digest();
17345            // the listener is always called during the first $digest loop after it was registered
17346            expect(scope.counter).toEqual(1);
17347
17348            scope.$digest();
17349            // but now it will not be called unless the value changes
17350            expect(scope.counter).toEqual(1);
17351
17352            scope.name = 'adam';
17353            scope.$digest();
17354            expect(scope.counter).toEqual(2);
17355
17356
17357
17358            // Using a function as a watchExpression
17359            var food;
17360            scope.foodCounter = 0;
17361            expect(scope.foodCounter).toEqual(0);
17362            scope.$watch(
17363              // This function returns the value being watched. It is called for each turn of the $digest loop
17364              function() { return food; },
17365              // This is the change listener, called when the value returned from the above function changes
17366              function(newValue, oldValue) {
17367                if ( newValue !== oldValue ) {
17368                  // Only increment the counter if the value changed
17369                  scope.foodCounter = scope.foodCounter + 1;
17370                }
17371              }
17372            );
17373            // No digest has been run so the counter will be zero
17374            expect(scope.foodCounter).toEqual(0);
17375
17376            // Run the digest but since food has not changed count will still be zero
17377            scope.$digest();
17378            expect(scope.foodCounter).toEqual(0);
17379
17380            // Update food and run digest.  Now the counter will increment
17381            food = 'cheeseburger';
17382            scope.$digest();
17383            expect(scope.foodCounter).toEqual(1);
17384
17385        * ```
17386        *
17387        *
17388        *
17389        * @param {(function()|string)} watchExpression Expression that is evaluated on each
17390        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
17391        *    a call to the `listener`.
17392        *
17393        *    - `string`: Evaluated as {@link guide/expression expression}
17394        *    - `function(scope)`: called with current `scope` as a parameter.
17395        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
17396        *    of `watchExpression` changes.
17397        *
17398        *    - `newVal` contains the current value of the `watchExpression`
17399        *    - `oldVal` contains the previous value of the `watchExpression`
17400        *    - `scope` refers to the current scope
17401        * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
17402        *     comparing for reference equality.
17403        * @returns {function()} Returns a deregistration function for this listener.
17404        */
17405       $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
17406         var get = $parse(watchExp);
17407
17408         if (get.$$watchDelegate) {
17409           return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
17410         }
17411         var scope = this,
17412             array = scope.$$watchers,
17413             watcher = {
17414               fn: listener,
17415               last: initWatchVal,
17416               get: get,
17417               exp: prettyPrintExpression || watchExp,
17418               eq: !!objectEquality
17419             };
17420
17421         lastDirtyWatch = null;
17422
17423         if (!isFunction(listener)) {
17424           watcher.fn = noop;
17425         }
17426
17427         if (!array) {
17428           array = scope.$$watchers = [];
17429           array.$$digestWatchIndex = -1;
17430         }
17431         // we use unshift since we use a while loop in $digest for speed.
17432         // the while loop reads in reverse order.
17433         array.unshift(watcher);
17434         array.$$digestWatchIndex++;
17435         incrementWatchersCount(this, 1);
17436
17437         return function deregisterWatch() {
17438           var index = arrayRemove(array, watcher);
17439           if (index >= 0) {
17440             incrementWatchersCount(scope, -1);
17441             if (index < array.$$digestWatchIndex) {
17442               array.$$digestWatchIndex--;
17443             }
17444           }
17445           lastDirtyWatch = null;
17446         };
17447       },
17448
17449       /**
17450        * @ngdoc method
17451        * @name $rootScope.Scope#$watchGroup
17452        * @kind function
17453        *
17454        * @description
17455        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
17456        * If any one expression in the collection changes the `listener` is executed.
17457        *
17458        * - The items in the `watchExpressions` array are observed via the standard `$watch` operation. Their return
17459        *   values are examined for changes on every call to `$digest`.
17460        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
17461        *
17462        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
17463        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
17464        *
17465        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
17466        *    expression in `watchExpressions` changes
17467        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
17468        *    those of `watchExpression`
17469        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
17470        *    those of `watchExpression`
17471        *    The `scope` refers to the current scope.
17472        * @returns {function()} Returns a de-registration function for all listeners.
17473        */
17474       $watchGroup: function(watchExpressions, listener) {
17475         var oldValues = new Array(watchExpressions.length);
17476         var newValues = new Array(watchExpressions.length);
17477         var deregisterFns = [];
17478         var self = this;
17479         var changeReactionScheduled = false;
17480         var firstRun = true;
17481
17482         if (!watchExpressions.length) {
17483           // No expressions means we call the listener ASAP
17484           var shouldCall = true;
17485           self.$evalAsync(function() {
17486             if (shouldCall) listener(newValues, newValues, self);
17487           });
17488           return function deregisterWatchGroup() {
17489             shouldCall = false;
17490           };
17491         }
17492
17493         if (watchExpressions.length === 1) {
17494           // Special case size of one
17495           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
17496             newValues[0] = value;
17497             oldValues[0] = oldValue;
17498             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
17499           });
17500         }
17501
17502         forEach(watchExpressions, function(expr, i) {
17503           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
17504             newValues[i] = value;
17505             oldValues[i] = oldValue;
17506             if (!changeReactionScheduled) {
17507               changeReactionScheduled = true;
17508               self.$evalAsync(watchGroupAction);
17509             }
17510           });
17511           deregisterFns.push(unwatchFn);
17512         });
17513
17514         function watchGroupAction() {
17515           changeReactionScheduled = false;
17516
17517           if (firstRun) {
17518             firstRun = false;
17519             listener(newValues, newValues, self);
17520           } else {
17521             listener(newValues, oldValues, self);
17522           }
17523         }
17524
17525         return function deregisterWatchGroup() {
17526           while (deregisterFns.length) {
17527             deregisterFns.shift()();
17528           }
17529         };
17530       },
17531
17532
17533       /**
17534        * @ngdoc method
17535        * @name $rootScope.Scope#$watchCollection
17536        * @kind function
17537        *
17538        * @description
17539        * Shallow watches the properties of an object and fires whenever any of the properties change
17540        * (for arrays, this implies watching the array items; for object maps, this implies watching
17541        * the properties). If a change is detected, the `listener` callback is fired.
17542        *
17543        * - The `obj` collection is observed via standard $watch operation and is examined on every
17544        *   call to $digest() to see if any items have been added, removed, or moved.
17545        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
17546        *   adding, removing, and moving items belonging to an object or array.
17547        *
17548        *
17549        * # Example
17550        * ```js
17551           $scope.names = ['igor', 'matias', 'misko', 'james'];
17552           $scope.dataCount = 4;
17553
17554           $scope.$watchCollection('names', function(newNames, oldNames) {
17555             $scope.dataCount = newNames.length;
17556           });
17557
17558           expect($scope.dataCount).toEqual(4);
17559           $scope.$digest();
17560
17561           //still at 4 ... no changes
17562           expect($scope.dataCount).toEqual(4);
17563
17564           $scope.names.pop();
17565           $scope.$digest();
17566
17567           //now there's been a change
17568           expect($scope.dataCount).toEqual(3);
17569        * ```
17570        *
17571        *
17572        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
17573        *    expression value should evaluate to an object or an array which is observed on each
17574        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
17575        *    collection will trigger a call to the `listener`.
17576        *
17577        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
17578        *    when a change is detected.
17579        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
17580        *    - The `oldCollection` object is a copy of the former collection data.
17581        *      Due to performance considerations, the`oldCollection` value is computed only if the
17582        *      `listener` function declares two or more arguments.
17583        *    - The `scope` argument refers to the current scope.
17584        *
17585        * @returns {function()} Returns a de-registration function for this listener. When the
17586        *    de-registration function is executed, the internal watch operation is terminated.
17587        */
17588       $watchCollection: function(obj, listener) {
17589         $watchCollectionInterceptor.$stateful = true;
17590
17591         var self = this;
17592         // the current value, updated on each dirty-check run
17593         var newValue;
17594         // a shallow copy of the newValue from the last dirty-check run,
17595         // updated to match newValue during dirty-check run
17596         var oldValue;
17597         // a shallow copy of the newValue from when the last change happened
17598         var veryOldValue;
17599         // only track veryOldValue if the listener is asking for it
17600         var trackVeryOldValue = (listener.length > 1);
17601         var changeDetected = 0;
17602         var changeDetector = $parse(obj, $watchCollectionInterceptor);
17603         var internalArray = [];
17604         var internalObject = {};
17605         var initRun = true;
17606         var oldLength = 0;
17607
17608         function $watchCollectionInterceptor(_value) {
17609           newValue = _value;
17610           var newLength, key, bothNaN, newItem, oldItem;
17611
17612           // If the new value is undefined, then return undefined as the watch may be a one-time watch
17613           if (isUndefined(newValue)) return;
17614
17615           if (!isObject(newValue)) { // if primitive
17616             if (oldValue !== newValue) {
17617               oldValue = newValue;
17618               changeDetected++;
17619             }
17620           } else if (isArrayLike(newValue)) {
17621             if (oldValue !== internalArray) {
17622               // we are transitioning from something which was not an array into array.
17623               oldValue = internalArray;
17624               oldLength = oldValue.length = 0;
17625               changeDetected++;
17626             }
17627
17628             newLength = newValue.length;
17629
17630             if (oldLength !== newLength) {
17631               // if lengths do not match we need to trigger change notification
17632               changeDetected++;
17633               oldValue.length = oldLength = newLength;
17634             }
17635             // copy the items to oldValue and look for changes.
17636             for (var i = 0; i < newLength; i++) {
17637               oldItem = oldValue[i];
17638               newItem = newValue[i];
17639
17640               // eslint-disable-next-line no-self-compare
17641               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
17642               if (!bothNaN && (oldItem !== newItem)) {
17643                 changeDetected++;
17644                 oldValue[i] = newItem;
17645               }
17646             }
17647           } else {
17648             if (oldValue !== internalObject) {
17649               // we are transitioning from something which was not an object into object.
17650               oldValue = internalObject = {};
17651               oldLength = 0;
17652               changeDetected++;
17653             }
17654             // copy the items to oldValue and look for changes.
17655             newLength = 0;
17656             for (key in newValue) {
17657               if (hasOwnProperty.call(newValue, key)) {
17658                 newLength++;
17659                 newItem = newValue[key];
17660                 oldItem = oldValue[key];
17661
17662                 if (key in oldValue) {
17663                   // eslint-disable-next-line no-self-compare
17664                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
17665                   if (!bothNaN && (oldItem !== newItem)) {
17666                     changeDetected++;
17667                     oldValue[key] = newItem;
17668                   }
17669                 } else {
17670                   oldLength++;
17671                   oldValue[key] = newItem;
17672                   changeDetected++;
17673                 }
17674               }
17675             }
17676             if (oldLength > newLength) {
17677               // we used to have more keys, need to find them and destroy them.
17678               changeDetected++;
17679               for (key in oldValue) {
17680                 if (!hasOwnProperty.call(newValue, key)) {
17681                   oldLength--;
17682                   delete oldValue[key];
17683                 }
17684               }
17685             }
17686           }
17687           return changeDetected;
17688         }
17689
17690         function $watchCollectionAction() {
17691           if (initRun) {
17692             initRun = false;
17693             listener(newValue, newValue, self);
17694           } else {
17695             listener(newValue, veryOldValue, self);
17696           }
17697
17698           // make a copy for the next time a collection is changed
17699           if (trackVeryOldValue) {
17700             if (!isObject(newValue)) {
17701               //primitive
17702               veryOldValue = newValue;
17703             } else if (isArrayLike(newValue)) {
17704               veryOldValue = new Array(newValue.length);
17705               for (var i = 0; i < newValue.length; i++) {
17706                 veryOldValue[i] = newValue[i];
17707               }
17708             } else { // if object
17709               veryOldValue = {};
17710               for (var key in newValue) {
17711                 if (hasOwnProperty.call(newValue, key)) {
17712                   veryOldValue[key] = newValue[key];
17713                 }
17714               }
17715             }
17716           }
17717         }
17718
17719         return this.$watch(changeDetector, $watchCollectionAction);
17720       },
17721
17722       /**
17723        * @ngdoc method
17724        * @name $rootScope.Scope#$digest
17725        * @kind function
17726        *
17727        * @description
17728        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
17729        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
17730        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
17731        * until no more listeners are firing. This means that it is possible to get into an infinite
17732        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
17733        * iterations exceeds 10.
17734        *
17735        * Usually, you don't call `$digest()` directly in
17736        * {@link ng.directive:ngController controllers} or in
17737        * {@link ng.$compileProvider#directive directives}.
17738        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
17739        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
17740        *
17741        * If you want to be notified whenever `$digest()` is called,
17742        * you can register a `watchExpression` function with
17743        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
17744        *
17745        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
17746        *
17747        * # Example
17748        * ```js
17749            var scope = ...;
17750            scope.name = 'misko';
17751            scope.counter = 0;
17752
17753            expect(scope.counter).toEqual(0);
17754            scope.$watch('name', function(newValue, oldValue) {
17755              scope.counter = scope.counter + 1;
17756            });
17757            expect(scope.counter).toEqual(0);
17758
17759            scope.$digest();
17760            // the listener is always called during the first $digest loop after it was registered
17761            expect(scope.counter).toEqual(1);
17762
17763            scope.$digest();
17764            // but now it will not be called unless the value changes
17765            expect(scope.counter).toEqual(1);
17766
17767            scope.name = 'adam';
17768            scope.$digest();
17769            expect(scope.counter).toEqual(2);
17770        * ```
17771        *
17772        */
17773       $digest: function() {
17774         var watch, value, last, fn, get,
17775             watchers,
17776             dirty, ttl = TTL,
17777             next, current, target = this,
17778             watchLog = [],
17779             logIdx, asyncTask;
17780
17781         beginPhase('$digest');
17782         // Check for changes to browser url that happened in sync before the call to $digest
17783         $browser.$$checkUrlChange();
17784
17785         if (this === $rootScope && applyAsyncId !== null) {
17786           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
17787           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
17788           $browser.defer.cancel(applyAsyncId);
17789           flushApplyAsync();
17790         }
17791
17792         lastDirtyWatch = null;
17793
17794         do { // "while dirty" loop
17795           dirty = false;
17796           current = target;
17797
17798           // It's safe for asyncQueuePosition to be a local variable here because this loop can't
17799           // be reentered recursively. Calling $digest from a function passed to $applyAsync would
17800           // lead to a '$digest already in progress' error.
17801           for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {
17802             try {
17803               asyncTask = asyncQueue[asyncQueuePosition];
17804               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
17805             } catch (e) {
17806               $exceptionHandler(e);
17807             }
17808             lastDirtyWatch = null;
17809           }
17810           asyncQueue.length = 0;
17811
17812           traverseScopesLoop:
17813           do { // "traverse the scopes" loop
17814             if ((watchers = current.$$watchers)) {
17815               // process our watches
17816               watchers.$$digestWatchIndex = watchers.length;
17817               while (watchers.$$digestWatchIndex--) {
17818                 try {
17819                   watch = watchers[watchers.$$digestWatchIndex];
17820                   // Most common watches are on primitives, in which case we can short
17821                   // circuit it with === operator, only when === fails do we use .equals
17822                   if (watch) {
17823                     get = watch.get;
17824                     if ((value = get(current)) !== (last = watch.last) &&
17825                         !(watch.eq
17826                             ? equals(value, last)
17827                             : (isNumberNaN(value) && isNumberNaN(last)))) {
17828                       dirty = true;
17829                       lastDirtyWatch = watch;
17830                       watch.last = watch.eq ? copy(value, null) : value;
17831                       fn = watch.fn;
17832                       fn(value, ((last === initWatchVal) ? value : last), current);
17833                       if (ttl < 5) {
17834                         logIdx = 4 - ttl;
17835                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
17836                         watchLog[logIdx].push({
17837                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
17838                           newVal: value,
17839                           oldVal: last
17840                         });
17841                       }
17842                     } else if (watch === lastDirtyWatch) {
17843                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
17844                       // have already been tested.
17845                       dirty = false;
17846                       break traverseScopesLoop;
17847                     }
17848                   }
17849                 } catch (e) {
17850                   $exceptionHandler(e);
17851                 }
17852               }
17853             }
17854
17855             // Insanity Warning: scope depth-first traversal
17856             // yes, this code is a bit crazy, but it works and we have tests to prove it!
17857             // this piece should be kept in sync with the traversal in $broadcast
17858             if (!(next = ((current.$$watchersCount && current.$$childHead) ||
17859                 (current !== target && current.$$nextSibling)))) {
17860               while (current !== target && !(next = current.$$nextSibling)) {
17861                 current = current.$parent;
17862               }
17863             }
17864           } while ((current = next));
17865
17866           // `break traverseScopesLoop;` takes us to here
17867
17868           if ((dirty || asyncQueue.length) && !(ttl--)) {
17869             clearPhase();
17870             throw $rootScopeMinErr('infdig',
17871                 '{0} $digest() iterations reached. Aborting!\n' +
17872                 'Watchers fired in the last 5 iterations: {1}',
17873                 TTL, watchLog);
17874           }
17875
17876         } while (dirty || asyncQueue.length);
17877
17878         clearPhase();
17879
17880         // postDigestQueuePosition isn't local here because this loop can be reentered recursively.
17881         while (postDigestQueuePosition < postDigestQueue.length) {
17882           try {
17883             postDigestQueue[postDigestQueuePosition++]();
17884           } catch (e) {
17885             $exceptionHandler(e);
17886           }
17887         }
17888         postDigestQueue.length = postDigestQueuePosition = 0;
17889       },
17890
17891
17892       /**
17893        * @ngdoc event
17894        * @name $rootScope.Scope#$destroy
17895        * @eventType broadcast on scope being destroyed
17896        *
17897        * @description
17898        * Broadcasted when a scope and its children are being destroyed.
17899        *
17900        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
17901        * clean up DOM bindings before an element is removed from the DOM.
17902        */
17903
17904       /**
17905        * @ngdoc method
17906        * @name $rootScope.Scope#$destroy
17907        * @kind function
17908        *
17909        * @description
17910        * Removes the current scope (and all of its children) from the parent scope. Removal implies
17911        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
17912        * propagate to the current scope and its children. Removal also implies that the current
17913        * scope is eligible for garbage collection.
17914        *
17915        * The `$destroy()` is usually used by directives such as
17916        * {@link ng.directive:ngRepeat ngRepeat} for managing the
17917        * unrolling of the loop.
17918        *
17919        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
17920        * Application code can register a `$destroy` event handler that will give it a chance to
17921        * perform any necessary cleanup.
17922        *
17923        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
17924        * clean up DOM bindings before an element is removed from the DOM.
17925        */
17926       $destroy: function() {
17927         // We can't destroy a scope that has been already destroyed.
17928         if (this.$$destroyed) return;
17929         var parent = this.$parent;
17930
17931         this.$broadcast('$destroy');
17932         this.$$destroyed = true;
17933
17934         if (this === $rootScope) {
17935           //Remove handlers attached to window when $rootScope is removed
17936           $browser.$$applicationDestroyed();
17937         }
17938
17939         incrementWatchersCount(this, -this.$$watchersCount);
17940         for (var eventName in this.$$listenerCount) {
17941           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
17942         }
17943
17944         // sever all the references to parent scopes (after this cleanup, the current scope should
17945         // not be retained by any of our references and should be eligible for garbage collection)
17946         if (parent && parent.$$childHead === this) parent.$$childHead = this.$$nextSibling;
17947         if (parent && parent.$$childTail === this) parent.$$childTail = this.$$prevSibling;
17948         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
17949         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
17950
17951         // Disable listeners, watchers and apply/digest methods
17952         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
17953         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
17954         this.$$listeners = {};
17955
17956         // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
17957         this.$$nextSibling = null;
17958         cleanUpScope(this);
17959       },
17960
17961       /**
17962        * @ngdoc method
17963        * @name $rootScope.Scope#$eval
17964        * @kind function
17965        *
17966        * @description
17967        * Executes the `expression` on the current scope and returns the result. Any exceptions in
17968        * the expression are propagated (uncaught). This is useful when evaluating Angular
17969        * expressions.
17970        *
17971        * # Example
17972        * ```js
17973            var scope = ng.$rootScope.Scope();
17974            scope.a = 1;
17975            scope.b = 2;
17976
17977            expect(scope.$eval('a+b')).toEqual(3);
17978            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
17979        * ```
17980        *
17981        * @param {(string|function())=} expression An angular expression to be executed.
17982        *
17983        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
17984        *    - `function(scope)`: execute the function with the current `scope` parameter.
17985        *
17986        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
17987        * @returns {*} The result of evaluating the expression.
17988        */
17989       $eval: function(expr, locals) {
17990         return $parse(expr)(this, locals);
17991       },
17992
17993       /**
17994        * @ngdoc method
17995        * @name $rootScope.Scope#$evalAsync
17996        * @kind function
17997        *
17998        * @description
17999        * Executes the expression on the current scope at a later point in time.
18000        *
18001        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
18002        * that:
18003        *
18004        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
18005        *     rendering).
18006        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
18007        *     `expression` execution.
18008        *
18009        * Any exceptions from the execution of the expression are forwarded to the
18010        * {@link ng.$exceptionHandler $exceptionHandler} service.
18011        *
18012        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
18013        * will be scheduled. However, it is encouraged to always call code that changes the model
18014        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
18015        *
18016        * @param {(string|function())=} expression An angular expression to be executed.
18017        *
18018        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
18019        *    - `function(scope)`: execute the function with the current `scope` parameter.
18020        *
18021        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
18022        */
18023       $evalAsync: function(expr, locals) {
18024         // if we are outside of an $digest loop and this is the first time we are scheduling async
18025         // task also schedule async auto-flush
18026         if (!$rootScope.$$phase && !asyncQueue.length) {
18027           $browser.defer(function() {
18028             if (asyncQueue.length) {
18029               $rootScope.$digest();
18030             }
18031           });
18032         }
18033
18034         asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
18035       },
18036
18037       $$postDigest: function(fn) {
18038         postDigestQueue.push(fn);
18039       },
18040
18041       /**
18042        * @ngdoc method
18043        * @name $rootScope.Scope#$apply
18044        * @kind function
18045        *
18046        * @description
18047        * `$apply()` is used to execute an expression in angular from outside of the angular
18048        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
18049        * Because we are calling into the angular framework we need to perform proper scope life
18050        * cycle of {@link ng.$exceptionHandler exception handling},
18051        * {@link ng.$rootScope.Scope#$digest executing watches}.
18052        *
18053        * ## Life cycle
18054        *
18055        * # Pseudo-Code of `$apply()`
18056        * ```js
18057            function $apply(expr) {
18058              try {
18059                return $eval(expr);
18060              } catch (e) {
18061                $exceptionHandler(e);
18062              } finally {
18063                $root.$digest();
18064              }
18065            }
18066        * ```
18067        *
18068        *
18069        * Scope's `$apply()` method transitions through the following stages:
18070        *
18071        * 1. The {@link guide/expression expression} is executed using the
18072        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
18073        * 2. Any exceptions from the execution of the expression are forwarded to the
18074        *    {@link ng.$exceptionHandler $exceptionHandler} service.
18075        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
18076        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
18077        *
18078        *
18079        * @param {(string|function())=} exp An angular expression to be executed.
18080        *
18081        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
18082        *    - `function(scope)`: execute the function with current `scope` parameter.
18083        *
18084        * @returns {*} The result of evaluating the expression.
18085        */
18086       $apply: function(expr) {
18087         try {
18088           beginPhase('$apply');
18089           try {
18090             return this.$eval(expr);
18091           } finally {
18092             clearPhase();
18093           }
18094         } catch (e) {
18095           $exceptionHandler(e);
18096         } finally {
18097           try {
18098             $rootScope.$digest();
18099           } catch (e) {
18100             $exceptionHandler(e);
18101             // eslint-disable-next-line no-unsafe-finally
18102             throw e;
18103           }
18104         }
18105       },
18106
18107       /**
18108        * @ngdoc method
18109        * @name $rootScope.Scope#$applyAsync
18110        * @kind function
18111        *
18112        * @description
18113        * Schedule the invocation of $apply to occur at a later time. The actual time difference
18114        * varies across browsers, but is typically around ~10 milliseconds.
18115        *
18116        * This can be used to queue up multiple expressions which need to be evaluated in the same
18117        * digest.
18118        *
18119        * @param {(string|function())=} exp An angular expression to be executed.
18120        *
18121        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
18122        *    - `function(scope)`: execute the function with current `scope` parameter.
18123        */
18124       $applyAsync: function(expr) {
18125         var scope = this;
18126         if (expr) {
18127           applyAsyncQueue.push($applyAsyncExpression);
18128         }
18129         expr = $parse(expr);
18130         scheduleApplyAsync();
18131
18132         function $applyAsyncExpression() {
18133           scope.$eval(expr);
18134         }
18135       },
18136
18137       /**
18138        * @ngdoc method
18139        * @name $rootScope.Scope#$on
18140        * @kind function
18141        *
18142        * @description
18143        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
18144        * discussion of event life cycle.
18145        *
18146        * The event listener function format is: `function(event, args...)`. The `event` object
18147        * passed into the listener has the following attributes:
18148        *
18149        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
18150        *     `$broadcast`-ed.
18151        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
18152        *     event propagates through the scope hierarchy, this property is set to null.
18153        *   - `name` - `{string}`: name of the event.
18154        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
18155        *     further event propagation (available only for events that were `$emit`-ed).
18156        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
18157        *     to true.
18158        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
18159        *
18160        * @param {string} name Event name to listen on.
18161        * @param {function(event, ...args)} listener Function to call when the event is emitted.
18162        * @returns {function()} Returns a deregistration function for this listener.
18163        */
18164       $on: function(name, listener) {
18165         var namedListeners = this.$$listeners[name];
18166         if (!namedListeners) {
18167           this.$$listeners[name] = namedListeners = [];
18168         }
18169         namedListeners.push(listener);
18170
18171         var current = this;
18172         do {
18173           if (!current.$$listenerCount[name]) {
18174             current.$$listenerCount[name] = 0;
18175           }
18176           current.$$listenerCount[name]++;
18177         } while ((current = current.$parent));
18178
18179         var self = this;
18180         return function() {
18181           var indexOfListener = namedListeners.indexOf(listener);
18182           if (indexOfListener !== -1) {
18183             namedListeners[indexOfListener] = null;
18184             decrementListenerCount(self, 1, name);
18185           }
18186         };
18187       },
18188
18189
18190       /**
18191        * @ngdoc method
18192        * @name $rootScope.Scope#$emit
18193        * @kind function
18194        *
18195        * @description
18196        * Dispatches an event `name` upwards through the scope hierarchy notifying the
18197        * registered {@link ng.$rootScope.Scope#$on} listeners.
18198        *
18199        * The event life cycle starts at the scope on which `$emit` was called. All
18200        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
18201        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
18202        * registered listeners along the way. The event will stop propagating if one of the listeners
18203        * cancels it.
18204        *
18205        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
18206        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
18207        *
18208        * @param {string} name Event name to emit.
18209        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
18210        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
18211        */
18212       $emit: function(name, args) {
18213         var empty = [],
18214             namedListeners,
18215             scope = this,
18216             stopPropagation = false,
18217             event = {
18218               name: name,
18219               targetScope: scope,
18220               stopPropagation: function() {stopPropagation = true;},
18221               preventDefault: function() {
18222                 event.defaultPrevented = true;
18223               },
18224               defaultPrevented: false
18225             },
18226             listenerArgs = concat([event], arguments, 1),
18227             i, length;
18228
18229         do {
18230           namedListeners = scope.$$listeners[name] || empty;
18231           event.currentScope = scope;
18232           for (i = 0, length = namedListeners.length; i < length; i++) {
18233
18234             // if listeners were deregistered, defragment the array
18235             if (!namedListeners[i]) {
18236               namedListeners.splice(i, 1);
18237               i--;
18238               length--;
18239               continue;
18240             }
18241             try {
18242               //allow all listeners attached to the current scope to run
18243               namedListeners[i].apply(null, listenerArgs);
18244             } catch (e) {
18245               $exceptionHandler(e);
18246             }
18247           }
18248           //if any listener on the current scope stops propagation, prevent bubbling
18249           if (stopPropagation) {
18250             event.currentScope = null;
18251             return event;
18252           }
18253           //traverse upwards
18254           scope = scope.$parent;
18255         } while (scope);
18256
18257         event.currentScope = null;
18258
18259         return event;
18260       },
18261
18262
18263       /**
18264        * @ngdoc method
18265        * @name $rootScope.Scope#$broadcast
18266        * @kind function
18267        *
18268        * @description
18269        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
18270        * registered {@link ng.$rootScope.Scope#$on} listeners.
18271        *
18272        * The event life cycle starts at the scope on which `$broadcast` was called. All
18273        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
18274        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
18275        * scope and calls all registered listeners along the way. The event cannot be canceled.
18276        *
18277        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
18278        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
18279        *
18280        * @param {string} name Event name to broadcast.
18281        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
18282        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
18283        */
18284       $broadcast: function(name, args) {
18285         var target = this,
18286             current = target,
18287             next = target,
18288             event = {
18289               name: name,
18290               targetScope: target,
18291               preventDefault: function() {
18292                 event.defaultPrevented = true;
18293               },
18294               defaultPrevented: false
18295             };
18296
18297         if (!target.$$listenerCount[name]) return event;
18298
18299         var listenerArgs = concat([event], arguments, 1),
18300             listeners, i, length;
18301
18302         //down while you can, then up and next sibling or up and next sibling until back at root
18303         while ((current = next)) {
18304           event.currentScope = current;
18305           listeners = current.$$listeners[name] || [];
18306           for (i = 0, length = listeners.length; i < length; i++) {
18307             // if listeners were deregistered, defragment the array
18308             if (!listeners[i]) {
18309               listeners.splice(i, 1);
18310               i--;
18311               length--;
18312               continue;
18313             }
18314
18315             try {
18316               listeners[i].apply(null, listenerArgs);
18317             } catch (e) {
18318               $exceptionHandler(e);
18319             }
18320           }
18321
18322           // Insanity Warning: scope depth-first traversal
18323           // yes, this code is a bit crazy, but it works and we have tests to prove it!
18324           // this piece should be kept in sync with the traversal in $digest
18325           // (though it differs due to having the extra check for $$listenerCount)
18326           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
18327               (current !== target && current.$$nextSibling)))) {
18328             while (current !== target && !(next = current.$$nextSibling)) {
18329               current = current.$parent;
18330             }
18331           }
18332         }
18333
18334         event.currentScope = null;
18335         return event;
18336       }
18337     };
18338
18339     var $rootScope = new Scope();
18340
18341     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
18342     var asyncQueue = $rootScope.$$asyncQueue = [];
18343     var postDigestQueue = $rootScope.$$postDigestQueue = [];
18344     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
18345
18346     var postDigestQueuePosition = 0;
18347
18348     return $rootScope;
18349
18350
18351     function beginPhase(phase) {
18352       if ($rootScope.$$phase) {
18353         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
18354       }
18355
18356       $rootScope.$$phase = phase;
18357     }
18358
18359     function clearPhase() {
18360       $rootScope.$$phase = null;
18361     }
18362
18363     function incrementWatchersCount(current, count) {
18364       do {
18365         current.$$watchersCount += count;
18366       } while ((current = current.$parent));
18367     }
18368
18369     function decrementListenerCount(current, count, name) {
18370       do {
18371         current.$$listenerCount[name] -= count;
18372
18373         if (current.$$listenerCount[name] === 0) {
18374           delete current.$$listenerCount[name];
18375         }
18376       } while ((current = current.$parent));
18377     }
18378
18379     /**
18380      * function used as an initial value for watchers.
18381      * because it's unique we can easily tell it apart from other values
18382      */
18383     function initWatchVal() {}
18384
18385     function flushApplyAsync() {
18386       while (applyAsyncQueue.length) {
18387         try {
18388           applyAsyncQueue.shift()();
18389         } catch (e) {
18390           $exceptionHandler(e);
18391         }
18392       }
18393       applyAsyncId = null;
18394     }
18395
18396     function scheduleApplyAsync() {
18397       if (applyAsyncId === null) {
18398         applyAsyncId = $browser.defer(function() {
18399           $rootScope.$apply(flushApplyAsync);
18400         });
18401       }
18402     }
18403   }];
18404 }
18405
18406 /**
18407  * @ngdoc service
18408  * @name $rootElement
18409  *
18410  * @description
18411  * The root element of Angular application. This is either the element where {@link
18412  * ng.directive:ngApp ngApp} was declared or the element passed into
18413  * {@link angular.bootstrap}. The element represents the root element of application. It is also the
18414  * location where the application's {@link auto.$injector $injector} service gets
18415  * published, and can be retrieved using `$rootElement.injector()`.
18416  */
18417
18418
18419 // the implementation is in angular.bootstrap
18420
18421 /**
18422  * @this
18423  * @description
18424  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
18425  */
18426 function $$SanitizeUriProvider() {
18427   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
18428     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
18429
18430   /**
18431    * @description
18432    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18433    * urls during a[href] sanitization.
18434    *
18435    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
18436    *
18437    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
18438    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
18439    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
18440    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18441    *
18442    * @param {RegExp=} regexp New regexp to whitelist urls with.
18443    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18444    *    chaining otherwise.
18445    */
18446   this.aHrefSanitizationWhitelist = function(regexp) {
18447     if (isDefined(regexp)) {
18448       aHrefSanitizationWhitelist = regexp;
18449       return this;
18450     }
18451     return aHrefSanitizationWhitelist;
18452   };
18453
18454
18455   /**
18456    * @description
18457    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18458    * urls during img[src] sanitization.
18459    *
18460    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
18461    *
18462    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
18463    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
18464    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
18465    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18466    *
18467    * @param {RegExp=} regexp New regexp to whitelist urls with.
18468    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18469    *    chaining otherwise.
18470    */
18471   this.imgSrcSanitizationWhitelist = function(regexp) {
18472     if (isDefined(regexp)) {
18473       imgSrcSanitizationWhitelist = regexp;
18474       return this;
18475     }
18476     return imgSrcSanitizationWhitelist;
18477   };
18478
18479   this.$get = function() {
18480     return function sanitizeUri(uri, isImage) {
18481       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
18482       var normalizedVal;
18483       normalizedVal = urlResolve(uri).href;
18484       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
18485         return 'unsafe:' + normalizedVal;
18486       }
18487       return uri;
18488     };
18489   };
18490 }
18491
18492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18493  *     Any commits to this file should be reviewed with security in mind.  *
18494  *   Changes to this file can potentially create security vulnerabilities. *
18495  *          An approval from 2 Core members with history of modifying      *
18496  *                         this file is required.                          *
18497  *                                                                         *
18498  *  Does the change somehow allow for arbitrary javascript to be executed? *
18499  *    Or allows for someone to change the prototype of built-in objects?   *
18500  *     Or gives undesired access to variables likes document or window?    *
18501  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18502
18503 /* exported $SceProvider, $SceDelegateProvider */
18504
18505 var $sceMinErr = minErr('$sce');
18506
18507 var SCE_CONTEXTS = {
18508   HTML: 'html',
18509   CSS: 'css',
18510   URL: 'url',
18511   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
18512   // url.  (e.g. ng-include, script src, templateUrl)
18513   RESOURCE_URL: 'resourceUrl',
18514   JS: 'js'
18515 };
18516
18517 // Helper functions follow.
18518
18519 function adjustMatcher(matcher) {
18520   if (matcher === 'self') {
18521     return matcher;
18522   } else if (isString(matcher)) {
18523     // Strings match exactly except for 2 wildcards - '*' and '**'.
18524     // '*' matches any character except those from the set ':/.?&'.
18525     // '**' matches any character (like .* in a RegExp).
18526     // More than 2 *'s raises an error as it's ill defined.
18527     if (matcher.indexOf('***') > -1) {
18528       throw $sceMinErr('iwcard',
18529           'Illegal sequence *** in string matcher.  String: {0}', matcher);
18530     }
18531     matcher = escapeForRegexp(matcher).
18532                   replace(/\\\*\\\*/g, '.*').
18533                   replace(/\\\*/g, '[^:/.?&;]*');
18534     return new RegExp('^' + matcher + '$');
18535   } else if (isRegExp(matcher)) {
18536     // The only other type of matcher allowed is a Regexp.
18537     // Match entire URL / disallow partial matches.
18538     // Flags are reset (i.e. no global, ignoreCase or multiline)
18539     return new RegExp('^' + matcher.source + '$');
18540   } else {
18541     throw $sceMinErr('imatcher',
18542         'Matchers may only be "self", string patterns or RegExp objects');
18543   }
18544 }
18545
18546
18547 function adjustMatchers(matchers) {
18548   var adjustedMatchers = [];
18549   if (isDefined(matchers)) {
18550     forEach(matchers, function(matcher) {
18551       adjustedMatchers.push(adjustMatcher(matcher));
18552     });
18553   }
18554   return adjustedMatchers;
18555 }
18556
18557
18558 /**
18559  * @ngdoc service
18560  * @name $sceDelegate
18561  * @kind function
18562  *
18563  * @description
18564  *
18565  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
18566  * Contextual Escaping (SCE)} services to AngularJS.
18567  *
18568  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
18569  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
18570  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
18571  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
18572  * work because `$sce` delegates to `$sceDelegate` for these operations.
18573  *
18574  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
18575  *
18576  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
18577  * can override it completely to change the behavior of `$sce`, the common case would
18578  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
18579  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
18580  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
18581  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
18582  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
18583  */
18584
18585 /**
18586  * @ngdoc provider
18587  * @name $sceDelegateProvider
18588  * @this
18589  *
18590  * @description
18591  *
18592  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
18593  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
18594  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
18595  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
18596  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
18597  *
18598  * For the general details about this service in Angular, read the main page for {@link ng.$sce
18599  * Strict Contextual Escaping (SCE)}.
18600  *
18601  * **Example**:  Consider the following case. <a name="example"></a>
18602  *
18603  * - your app is hosted at url `http://myapp.example.com/`
18604  * - but some of your templates are hosted on other domains you control such as
18605  *   `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc.
18606  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
18607  *
18608  * Here is what a secure configuration for this scenario might look like:
18609  *
18610  * ```
18611  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
18612  *    $sceDelegateProvider.resourceUrlWhitelist([
18613  *      // Allow same origin resource loads.
18614  *      'self',
18615  *      // Allow loading from our assets domain.  Notice the difference between * and **.
18616  *      'http://srv*.assets.example.com/**'
18617  *    ]);
18618  *
18619  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
18620  *    $sceDelegateProvider.resourceUrlBlacklist([
18621  *      'http://myapp.example.com/clickThru**'
18622  *    ]);
18623  *  });
18624  * ```
18625  */
18626
18627 function $SceDelegateProvider() {
18628   this.SCE_CONTEXTS = SCE_CONTEXTS;
18629
18630   // Resource URLs can also be trusted by policy.
18631   var resourceUrlWhitelist = ['self'],
18632       resourceUrlBlacklist = [];
18633
18634   /**
18635    * @ngdoc method
18636    * @name $sceDelegateProvider#resourceUrlWhitelist
18637    * @kind function
18638    *
18639    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
18640    *    provided.  This must be an array or null.  A snapshot of this array is used so further
18641    *    changes to the array are ignored.
18642    *
18643    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
18644    *    allowed in this array.
18645    *
18646    *    <div class="alert alert-warning">
18647    *    **Note:** an empty whitelist array will block all URLs!
18648    *    </div>
18649    *
18650    * @return {Array} the currently set whitelist array.
18651    *
18652    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
18653    * same origin resource requests.
18654    *
18655    * @description
18656    * Sets/Gets the whitelist of trusted resource URLs.
18657    */
18658   this.resourceUrlWhitelist = function(value) {
18659     if (arguments.length) {
18660       resourceUrlWhitelist = adjustMatchers(value);
18661     }
18662     return resourceUrlWhitelist;
18663   };
18664
18665   /**
18666    * @ngdoc method
18667    * @name $sceDelegateProvider#resourceUrlBlacklist
18668    * @kind function
18669    *
18670    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
18671    *    provided.  This must be an array or null.  A snapshot of this array is used so further
18672    *    changes to the array are ignored.
18673    *
18674    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
18675    *    allowed in this array.
18676    *
18677    *    The typical usage for the blacklist is to **block
18678    *    [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
18679    *    these would otherwise be trusted but actually return content from the redirected domain.
18680    *
18681    *    Finally, **the blacklist overrides the whitelist** and has the final say.
18682    *
18683    * @return {Array} the currently set blacklist array.
18684    *
18685    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
18686    * is no blacklist.)
18687    *
18688    * @description
18689    * Sets/Gets the blacklist of trusted resource URLs.
18690    */
18691
18692   this.resourceUrlBlacklist = function(value) {
18693     if (arguments.length) {
18694       resourceUrlBlacklist = adjustMatchers(value);
18695     }
18696     return resourceUrlBlacklist;
18697   };
18698
18699   this.$get = ['$injector', function($injector) {
18700
18701     var htmlSanitizer = function htmlSanitizer(html) {
18702       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
18703     };
18704
18705     if ($injector.has('$sanitize')) {
18706       htmlSanitizer = $injector.get('$sanitize');
18707     }
18708
18709
18710     function matchUrl(matcher, parsedUrl) {
18711       if (matcher === 'self') {
18712         return urlIsSameOrigin(parsedUrl);
18713       } else {
18714         // definitely a regex.  See adjustMatchers()
18715         return !!matcher.exec(parsedUrl.href);
18716       }
18717     }
18718
18719     function isResourceUrlAllowedByPolicy(url) {
18720       var parsedUrl = urlResolve(url.toString());
18721       var i, n, allowed = false;
18722       // Ensure that at least one item from the whitelist allows this url.
18723       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
18724         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
18725           allowed = true;
18726           break;
18727         }
18728       }
18729       if (allowed) {
18730         // Ensure that no item from the blacklist blocked this url.
18731         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
18732           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
18733             allowed = false;
18734             break;
18735           }
18736         }
18737       }
18738       return allowed;
18739     }
18740
18741     function generateHolderType(Base) {
18742       var holderType = function TrustedValueHolderType(trustedValue) {
18743         this.$$unwrapTrustedValue = function() {
18744           return trustedValue;
18745         };
18746       };
18747       if (Base) {
18748         holderType.prototype = new Base();
18749       }
18750       holderType.prototype.valueOf = function sceValueOf() {
18751         return this.$$unwrapTrustedValue();
18752       };
18753       holderType.prototype.toString = function sceToString() {
18754         return this.$$unwrapTrustedValue().toString();
18755       };
18756       return holderType;
18757     }
18758
18759     var trustedValueHolderBase = generateHolderType(),
18760         byType = {};
18761
18762     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
18763     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
18764     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
18765     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
18766     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
18767
18768     /**
18769      * @ngdoc method
18770      * @name $sceDelegate#trustAs
18771      *
18772      * @description
18773      * Returns an object that is trusted by angular for use in specified strict
18774      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
18775      * attribute interpolation, any dom event binding attribute interpolation
18776      * such as for onclick,  etc.) that uses the provided value.
18777      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
18778      *
18779      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
18780      *   resourceUrl, html, js and css.
18781      * @param {*} value The value that that should be considered trusted/safe.
18782      * @returns {*} A value that can be used to stand in for the provided `value` in places
18783      * where Angular expects a $sce.trustAs() return value.
18784      */
18785     function trustAs(type, trustedValue) {
18786       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
18787       if (!Constructor) {
18788         throw $sceMinErr('icontext',
18789             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
18790             type, trustedValue);
18791       }
18792       if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
18793         return trustedValue;
18794       }
18795       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
18796       // mutable objects, we ensure here that the value passed in is actually a string.
18797       if (typeof trustedValue !== 'string') {
18798         throw $sceMinErr('itype',
18799             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
18800             type);
18801       }
18802       return new Constructor(trustedValue);
18803     }
18804
18805     /**
18806      * @ngdoc method
18807      * @name $sceDelegate#valueOf
18808      *
18809      * @description
18810      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
18811      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
18812      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
18813      *
18814      * If the passed parameter is not a value that had been returned by {@link
18815      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
18816      *
18817      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
18818      *      call or anything else.
18819      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
18820      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
18821      *     `value` unchanged.
18822      */
18823     function valueOf(maybeTrusted) {
18824       if (maybeTrusted instanceof trustedValueHolderBase) {
18825         return maybeTrusted.$$unwrapTrustedValue();
18826       } else {
18827         return maybeTrusted;
18828       }
18829     }
18830
18831     /**
18832      * @ngdoc method
18833      * @name $sceDelegate#getTrusted
18834      *
18835      * @description
18836      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
18837      * returns the originally supplied value if the queried context type is a supertype of the
18838      * created type.  If this condition isn't satisfied, throws an exception.
18839      *
18840      * <div class="alert alert-danger">
18841      * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
18842      * (XSS) vulnerability in your application.
18843      * </div>
18844      *
18845      * @param {string} type The kind of context in which this value is to be used.
18846      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
18847      *     `$sceDelegate.trustAs`} call.
18848      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
18849      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
18850      */
18851     function getTrusted(type, maybeTrusted) {
18852       if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
18853         return maybeTrusted;
18854       }
18855       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
18856       if (constructor && maybeTrusted instanceof constructor) {
18857         return maybeTrusted.$$unwrapTrustedValue();
18858       }
18859       // If we get here, then we may only take one of two actions.
18860       // 1. sanitize the value for the requested type, or
18861       // 2. throw an exception.
18862       if (type === SCE_CONTEXTS.RESOURCE_URL) {
18863         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
18864           return maybeTrusted;
18865         } else {
18866           throw $sceMinErr('insecurl',
18867               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
18868               maybeTrusted.toString());
18869         }
18870       } else if (type === SCE_CONTEXTS.HTML) {
18871         return htmlSanitizer(maybeTrusted);
18872       }
18873       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
18874     }
18875
18876     return { trustAs: trustAs,
18877              getTrusted: getTrusted,
18878              valueOf: valueOf };
18879   }];
18880 }
18881
18882
18883 /**
18884  * @ngdoc provider
18885  * @name $sceProvider
18886  * @this
18887  *
18888  * @description
18889  *
18890  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
18891  * -   enable/disable Strict Contextual Escaping (SCE) in a module
18892  * -   override the default implementation with a custom delegate
18893  *
18894  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
18895  */
18896
18897 /**
18898  * @ngdoc service
18899  * @name $sce
18900  * @kind function
18901  *
18902  * @description
18903  *
18904  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
18905  *
18906  * # Strict Contextual Escaping
18907  *
18908  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
18909  * contexts to result in a value that is marked as safe to use for that context.  One example of
18910  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
18911  * to these contexts as privileged or SCE contexts.
18912  *
18913  * As of version 1.2, Angular ships with SCE enabled by default.
18914  *
18915  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
18916  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
18917  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
18918  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
18919  * to the top of your HTML document.
18920  *
18921  * SCE assists in writing code in a way that (a) is secure by default and (b) makes auditing for
18922  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
18923  *
18924  * Here's an example of a binding in a privileged context:
18925  *
18926  * ```
18927  * <input ng-model="userHtml" aria-label="User input">
18928  * <div ng-bind-html="userHtml"></div>
18929  * ```
18930  *
18931  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
18932  * disabled, this application allows the user to render arbitrary HTML into the DIV.
18933  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
18934  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
18935  * security vulnerabilities.)
18936  *
18937  * For the case of HTML, you might use a library, either on the client side, or on the server side,
18938  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
18939  *
18940  * How would you ensure that every place that used these types of bindings was bound to a value that
18941  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
18942  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
18943  * properties/fields and forgot to update the binding to the sanitized value?
18944  *
18945  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
18946  * determine that something explicitly says it's safe to use a value for binding in that
18947  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
18948  * for those values that you can easily tell are safe - because they were received from your server,
18949  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
18950  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
18951  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
18952  *
18953  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
18954  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
18955  * obtain values that will be accepted by SCE / privileged contexts.
18956  *
18957  *
18958  * ## How does it work?
18959  *
18960  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
18961  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
18962  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
18963  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
18964  *
18965  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
18966  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
18967  * simplified):
18968  *
18969  * ```
18970  * var ngBindHtmlDirective = ['$sce', function($sce) {
18971  *   return function(scope, element, attr) {
18972  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
18973  *       element.html(value || '');
18974  *     });
18975  *   };
18976  * }];
18977  * ```
18978  *
18979  * ## Impact on loading templates
18980  *
18981  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
18982  * `templateUrl`'s specified by {@link guide/directive directives}.
18983  *
18984  * By default, Angular only loads templates from the same domain and protocol as the application
18985  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
18986  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
18987  * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
18988  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
18989  *
18990  * *Please note*:
18991  * The browser's
18992  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
18993  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
18994  * policy apply in addition to this and may further restrict whether the template is successfully
18995  * loaded.  This means that without the right CORS policy, loading templates from a different domain
18996  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
18997  * browsers.
18998  *
18999  * ## This feels like too much overhead
19000  *
19001  * It's important to remember that SCE only applies to interpolation expressions.
19002  *
19003  * If your expressions are constant literals, they're automatically trusted and you don't need to
19004  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
19005  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
19006  *
19007  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
19008  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
19009  *
19010  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
19011  * templates in `ng-include` from your application's domain without having to even know about SCE.
19012  * It blocks loading templates from other domains or loading templates over http from an https
19013  * served document.  You can change these by setting your own custom {@link
19014  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
19015  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
19016  *
19017  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
19018  * application that's secure and can be audited to verify that with much more ease than bolting
19019  * security onto an application later.
19020  *
19021  * <a name="contexts"></a>
19022  * ## What trusted context types are supported?
19023  *
19024  * | Context             | Notes          |
19025  * |---------------------|----------------|
19026  * | `$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. |
19027  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
19028  * | `$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. |
19029  * | `$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`, `VIDEO`, `AUDIO`, `SOURCE`, and `TRACK` (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. |
19030  * | `$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. |
19031  *
19032  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
19033  *
19034  *  Each element in these arrays must be one of the following:
19035  *
19036  *  - **'self'**
19037  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
19038  *      domain** as the application document using the **same protocol**.
19039  *  - **String** (except the special value `'self'`)
19040  *    - The string is matched against the full *normalized / absolute URL* of the resource
19041  *      being tested (substring matches are not good enough.)
19042  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
19043  *      match themselves.
19044  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
19045  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
19046  *      in a whitelist.
19047  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
19048  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
19049  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
19050  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
19051  *      http://foo.example.com/templates/**).
19052  *  - **RegExp** (*see caveat below*)
19053  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
19054  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
19055  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
19056  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
19057  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
19058  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
19059  *      is highly recommended to use the string patterns and only fall back to regular expressions
19060  *      as a last resort.
19061  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
19062  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
19063  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
19064  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
19065  *    - If you are generating your JavaScript from some other templating engine (not
19066  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
19067  *      remember to escape your regular expression (and be aware that you might need more than
19068  *      one level of escaping depending on your templating engine and the way you interpolated
19069  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
19070  *      enough before coding your own.  E.g. Ruby has
19071  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
19072  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
19073  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
19074  *      Closure library's [goog.string.regExpEscape(s)](
19075  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
19076  *
19077  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
19078  *
19079  * ## Show me an example using SCE.
19080  *
19081  * <example module="mySceApp" deps="angular-sanitize.js" name="sce-service">
19082  * <file name="index.html">
19083  *   <div ng-controller="AppController as myCtrl">
19084  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
19085  *     <b>User comments</b><br>
19086  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
19087  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
19088  *     exploit.
19089  *     <div class="well">
19090  *       <div ng-repeat="userComment in myCtrl.userComments">
19091  *         <b>{{userComment.name}}</b>:
19092  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
19093  *         <br>
19094  *       </div>
19095  *     </div>
19096  *   </div>
19097  * </file>
19098  *
19099  * <file name="script.js">
19100  *   angular.module('mySceApp', ['ngSanitize'])
19101  *     .controller('AppController', ['$http', '$templateCache', '$sce',
19102  *       function AppController($http, $templateCache, $sce) {
19103  *         var self = this;
19104  *         $http.get('test_data.json', {cache: $templateCache}).success(function(userComments) {
19105  *           self.userComments = userComments;
19106  *         });
19107  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
19108  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
19109  *             'sanitization.&quot;">Hover over this text.</span>');
19110  *       }]);
19111  * </file>
19112  *
19113  * <file name="test_data.json">
19114  * [
19115  *   { "name": "Alice",
19116  *     "htmlComment":
19117  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
19118  *   },
19119  *   { "name": "Bob",
19120  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
19121  *   }
19122  * ]
19123  * </file>
19124  *
19125  * <file name="protractor.js" type="protractor">
19126  *   describe('SCE doc demo', function() {
19127  *     it('should sanitize untrusted values', function() {
19128  *       expect(element.all(by.css('.htmlComment')).first().getAttribute('innerHTML'))
19129  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
19130  *     });
19131  *
19132  *     it('should NOT sanitize explicitly trusted values', function() {
19133  *       expect(element(by.id('explicitlyTrustedHtml')).getAttribute('innerHTML')).toBe(
19134  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
19135  *           'sanitization.&quot;">Hover over this text.</span>');
19136  *     });
19137  *   });
19138  * </file>
19139  * </example>
19140  *
19141  *
19142  *
19143  * ## Can I disable SCE completely?
19144  *
19145  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
19146  * for little coding overhead.  It will be much harder to take an SCE disabled application and
19147  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
19148  * for cases where you have a lot of existing code that was written before SCE was introduced and
19149  * you're migrating them a module at a time.
19150  *
19151  * That said, here's how you can completely disable SCE:
19152  *
19153  * ```
19154  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
19155  *   // Completely disable SCE.  For demonstration purposes only!
19156  *   // Do not use in new projects.
19157  *   $sceProvider.enabled(false);
19158  * });
19159  * ```
19160  *
19161  */
19162
19163 function $SceProvider() {
19164   var enabled = true;
19165
19166   /**
19167    * @ngdoc method
19168    * @name $sceProvider#enabled
19169    * @kind function
19170    *
19171    * @param {boolean=} value If provided, then enables/disables SCE.
19172    * @return {boolean} true if SCE is enabled, false otherwise.
19173    *
19174    * @description
19175    * Enables/disables SCE and returns the current value.
19176    */
19177   this.enabled = function(value) {
19178     if (arguments.length) {
19179       enabled = !!value;
19180     }
19181     return enabled;
19182   };
19183
19184
19185   /* Design notes on the default implementation for SCE.
19186    *
19187    * The API contract for the SCE delegate
19188    * -------------------------------------
19189    * The SCE delegate object must provide the following 3 methods:
19190    *
19191    * - trustAs(contextEnum, value)
19192    *     This method is used to tell the SCE service that the provided value is OK to use in the
19193    *     contexts specified by contextEnum.  It must return an object that will be accepted by
19194    *     getTrusted() for a compatible contextEnum and return this value.
19195    *
19196    * - valueOf(value)
19197    *     For values that were not produced by trustAs(), return them as is.  For values that were
19198    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
19199    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
19200    *     such a value.
19201    *
19202    * - getTrusted(contextEnum, value)
19203    *     This function should return the a value that is safe to use in the context specified by
19204    *     contextEnum or throw and exception otherwise.
19205    *
19206    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
19207    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
19208    * instance, an implementation could maintain a registry of all trusted objects by context.  In
19209    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
19210    * return the same object passed in if it was found in the registry under a compatible context or
19211    * throw an exception otherwise.  An implementation might only wrap values some of the time based
19212    * on some criteria.  getTrusted() might return a value and not throw an exception for special
19213    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
19214    *
19215    *
19216    * A note on the inheritance model for SCE contexts
19217    * ------------------------------------------------
19218    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
19219    * is purely an implementation details.
19220    *
19221    * The contract is simply this:
19222    *
19223    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
19224    *     will also succeed.
19225    *
19226    * Inheritance happens to capture this in a natural way.  In some future, we
19227    * may not use inheritance anymore.  That is OK because no code outside of
19228    * sce.js and sceSpecs.js would need to be aware of this detail.
19229    */
19230
19231   this.$get = ['$parse', '$sceDelegate', function(
19232                 $parse,   $sceDelegate) {
19233     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
19234     // the "expression(javascript expression)" syntax which is insecure.
19235     if (enabled && msie < 8) {
19236       throw $sceMinErr('iequirks',
19237         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
19238         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
19239         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
19240     }
19241
19242     var sce = shallowCopy(SCE_CONTEXTS);
19243
19244     /**
19245      * @ngdoc method
19246      * @name $sce#isEnabled
19247      * @kind function
19248      *
19249      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
19250      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
19251      *
19252      * @description
19253      * Returns a boolean indicating if SCE is enabled.
19254      */
19255     sce.isEnabled = function() {
19256       return enabled;
19257     };
19258     sce.trustAs = $sceDelegate.trustAs;
19259     sce.getTrusted = $sceDelegate.getTrusted;
19260     sce.valueOf = $sceDelegate.valueOf;
19261
19262     if (!enabled) {
19263       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
19264       sce.valueOf = identity;
19265     }
19266
19267     /**
19268      * @ngdoc method
19269      * @name $sce#parseAs
19270      *
19271      * @description
19272      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
19273      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
19274      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
19275      * *result*)}
19276      *
19277      * @param {string} type The kind of SCE context in which this result will be used.
19278      * @param {string} expression String expression to compile.
19279      * @returns {function(context, locals)} a function which represents the compiled expression:
19280      *
19281      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19282      *      are evaluated against (typically a scope object).
19283      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19284      *      `context`.
19285      */
19286     sce.parseAs = function sceParseAs(type, expr) {
19287       var parsed = $parse(expr);
19288       if (parsed.literal && parsed.constant) {
19289         return parsed;
19290       } else {
19291         return $parse(expr, function(value) {
19292           return sce.getTrusted(type, value);
19293         });
19294       }
19295     };
19296
19297     /**
19298      * @ngdoc method
19299      * @name $sce#trustAs
19300      *
19301      * @description
19302      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
19303      * returns an object that is trusted by angular for use in specified strict contextual
19304      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
19305      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
19306      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
19307      * escaping.
19308      *
19309      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
19310      *   resourceUrl, html, js and css.
19311      * @param {*} value The value that that should be considered trusted/safe.
19312      * @returns {*} A value that can be used to stand in for the provided `value` in places
19313      * where Angular expects a $sce.trustAs() return value.
19314      */
19315
19316     /**
19317      * @ngdoc method
19318      * @name $sce#trustAsHtml
19319      *
19320      * @description
19321      * Shorthand method.  `$sce.trustAsHtml(value)` â†’
19322      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
19323      *
19324      * @param {*} value The value to trustAs.
19325      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
19326      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
19327      *     only accept expressions that are either literal constants or are the
19328      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
19329      */
19330
19331     /**
19332      * @ngdoc method
19333      * @name $sce#trustAsUrl
19334      *
19335      * @description
19336      * Shorthand method.  `$sce.trustAsUrl(value)` â†’
19337      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
19338      *
19339      * @param {*} value The value to trustAs.
19340      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
19341      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
19342      *     only accept expressions that are either literal constants or are the
19343      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
19344      */
19345
19346     /**
19347      * @ngdoc method
19348      * @name $sce#trustAsResourceUrl
19349      *
19350      * @description
19351      * Shorthand method.  `$sce.trustAsResourceUrl(value)` â†’
19352      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
19353      *
19354      * @param {*} value The value to trustAs.
19355      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
19356      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
19357      *     only accept expressions that are either literal constants or are the return
19358      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
19359      */
19360
19361     /**
19362      * @ngdoc method
19363      * @name $sce#trustAsJs
19364      *
19365      * @description
19366      * Shorthand method.  `$sce.trustAsJs(value)` â†’
19367      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
19368      *
19369      * @param {*} value The value to trustAs.
19370      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
19371      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
19372      *     only accept expressions that are either literal constants or are the
19373      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
19374      */
19375
19376     /**
19377      * @ngdoc method
19378      * @name $sce#getTrusted
19379      *
19380      * @description
19381      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
19382      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
19383      * originally supplied value if the queried context type is a supertype of the created type.
19384      * If this condition isn't satisfied, throws an exception.
19385      *
19386      * @param {string} type The kind of context in which this value is to be used.
19387      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
19388      *                         call.
19389      * @returns {*} The value the was originally provided to
19390      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
19391      *              Otherwise, throws an exception.
19392      */
19393
19394     /**
19395      * @ngdoc method
19396      * @name $sce#getTrustedHtml
19397      *
19398      * @description
19399      * Shorthand method.  `$sce.getTrustedHtml(value)` â†’
19400      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
19401      *
19402      * @param {*} value The value to pass to `$sce.getTrusted`.
19403      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
19404      */
19405
19406     /**
19407      * @ngdoc method
19408      * @name $sce#getTrustedCss
19409      *
19410      * @description
19411      * Shorthand method.  `$sce.getTrustedCss(value)` â†’
19412      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
19413      *
19414      * @param {*} value The value to pass to `$sce.getTrusted`.
19415      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
19416      */
19417
19418     /**
19419      * @ngdoc method
19420      * @name $sce#getTrustedUrl
19421      *
19422      * @description
19423      * Shorthand method.  `$sce.getTrustedUrl(value)` â†’
19424      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
19425      *
19426      * @param {*} value The value to pass to `$sce.getTrusted`.
19427      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
19428      */
19429
19430     /**
19431      * @ngdoc method
19432      * @name $sce#getTrustedResourceUrl
19433      *
19434      * @description
19435      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` â†’
19436      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
19437      *
19438      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
19439      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
19440      */
19441
19442     /**
19443      * @ngdoc method
19444      * @name $sce#getTrustedJs
19445      *
19446      * @description
19447      * Shorthand method.  `$sce.getTrustedJs(value)` â†’
19448      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
19449      *
19450      * @param {*} value The value to pass to `$sce.getTrusted`.
19451      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
19452      */
19453
19454     /**
19455      * @ngdoc method
19456      * @name $sce#parseAsHtml
19457      *
19458      * @description
19459      * Shorthand method.  `$sce.parseAsHtml(expression string)` â†’
19460      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
19461      *
19462      * @param {string} expression String expression to compile.
19463      * @returns {function(context, locals)} a function which represents the compiled expression:
19464      *
19465      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19466      *      are evaluated against (typically a scope object).
19467      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19468      *      `context`.
19469      */
19470
19471     /**
19472      * @ngdoc method
19473      * @name $sce#parseAsCss
19474      *
19475      * @description
19476      * Shorthand method.  `$sce.parseAsCss(value)` â†’
19477      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
19478      *
19479      * @param {string} expression String expression to compile.
19480      * @returns {function(context, locals)} a function which represents the compiled expression:
19481      *
19482      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19483      *      are evaluated against (typically a scope object).
19484      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19485      *      `context`.
19486      */
19487
19488     /**
19489      * @ngdoc method
19490      * @name $sce#parseAsUrl
19491      *
19492      * @description
19493      * Shorthand method.  `$sce.parseAsUrl(value)` â†’
19494      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
19495      *
19496      * @param {string} expression String expression to compile.
19497      * @returns {function(context, locals)} a function which represents the compiled expression:
19498      *
19499      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19500      *      are evaluated against (typically a scope object).
19501      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19502      *      `context`.
19503      */
19504
19505     /**
19506      * @ngdoc method
19507      * @name $sce#parseAsResourceUrl
19508      *
19509      * @description
19510      * Shorthand method.  `$sce.parseAsResourceUrl(value)` â†’
19511      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
19512      *
19513      * @param {string} expression String expression to compile.
19514      * @returns {function(context, locals)} a function which represents the compiled expression:
19515      *
19516      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19517      *      are evaluated against (typically a scope object).
19518      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19519      *      `context`.
19520      */
19521
19522     /**
19523      * @ngdoc method
19524      * @name $sce#parseAsJs
19525      *
19526      * @description
19527      * Shorthand method.  `$sce.parseAsJs(value)` â†’
19528      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
19529      *
19530      * @param {string} expression String expression to compile.
19531      * @returns {function(context, locals)} a function which represents the compiled expression:
19532      *
19533      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
19534      *      are evaluated against (typically a scope object).
19535      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
19536      *      `context`.
19537      */
19538
19539     // Shorthand delegations.
19540     var parse = sce.parseAs,
19541         getTrusted = sce.getTrusted,
19542         trustAs = sce.trustAs;
19543
19544     forEach(SCE_CONTEXTS, function(enumValue, name) {
19545       var lName = lowercase(name);
19546       sce[camelCase('parse_as_' + lName)] = function(expr) {
19547         return parse(enumValue, expr);
19548       };
19549       sce[camelCase('get_trusted_' + lName)] = function(value) {
19550         return getTrusted(enumValue, value);
19551       };
19552       sce[camelCase('trust_as_' + lName)] = function(value) {
19553         return trustAs(enumValue, value);
19554       };
19555     });
19556
19557     return sce;
19558   }];
19559 }
19560
19561 /* exported $SnifferProvider */
19562
19563 /**
19564  * !!! This is an undocumented "private" service !!!
19565  *
19566  * @name $sniffer
19567  * @requires $window
19568  * @requires $document
19569  * @this
19570  *
19571  * @property {boolean} history Does the browser support html5 history api ?
19572  * @property {boolean} transitions Does the browser support CSS transition events ?
19573  * @property {boolean} animations Does the browser support CSS animation events ?
19574  *
19575  * @description
19576  * This is very simple implementation of testing browser's features.
19577  */
19578 function $SnifferProvider() {
19579   this.$get = ['$window', '$document', function($window, $document) {
19580     var eventSupport = {},
19581         // Chrome Packaged Apps are not allowed to access `history.pushState`.
19582         // If not sandboxed, they can be detected by the presence of `chrome.app.runtime`
19583         // (see https://developer.chrome.com/apps/api_index). If sandboxed, they can be detected by
19584         // the presence of an extension runtime ID and the absence of other Chrome runtime APIs
19585         // (see https://developer.chrome.com/apps/manifest/sandbox).
19586         isChromePackagedApp =
19587             $window.chrome &&
19588             ($window.chrome.app && $window.chrome.app.runtime ||
19589                 !$window.chrome.app && $window.chrome.runtime && $window.chrome.runtime.id),
19590         hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,
19591         android =
19592           toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
19593         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
19594         document = $document[0] || {},
19595         vendorPrefix,
19596         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
19597         bodyStyle = document.body && document.body.style,
19598         transitions = false,
19599         animations = false,
19600         match;
19601
19602     if (bodyStyle) {
19603       for (var prop in bodyStyle) {
19604         if ((match = vendorRegex.exec(prop))) {
19605           vendorPrefix = match[0];
19606           vendorPrefix = vendorPrefix[0].toUpperCase() + vendorPrefix.substr(1);
19607           break;
19608         }
19609       }
19610
19611       if (!vendorPrefix) {
19612         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
19613       }
19614
19615       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
19616       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
19617
19618       if (android && (!transitions ||  !animations)) {
19619         transitions = isString(bodyStyle.webkitTransition);
19620         animations = isString(bodyStyle.webkitAnimation);
19621       }
19622     }
19623
19624
19625     return {
19626       // Android has history.pushState, but it does not update location correctly
19627       // so let's not use the history API at all.
19628       // http://code.google.com/p/android/issues/detail?id=17471
19629       // https://github.com/angular/angular.js/issues/904
19630
19631       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
19632       // so let's not use the history API also
19633       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
19634       history: !!(hasHistoryPushState && !(android < 4) && !boxee),
19635       hasEvent: function(event) {
19636         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
19637         // it. In particular the event is not fired when backspace or delete key are pressed or
19638         // when cut operation is performed.
19639         // IE10+ implements 'input' event but it erroneously fires under various situations,
19640         // e.g. when placeholder changes, or a form is focused.
19641         if (event === 'input' && msie <= 11) return false;
19642
19643         if (isUndefined(eventSupport[event])) {
19644           var divElm = document.createElement('div');
19645           eventSupport[event] = 'on' + event in divElm;
19646         }
19647
19648         return eventSupport[event];
19649       },
19650       csp: csp(),
19651       vendorPrefix: vendorPrefix,
19652       transitions: transitions,
19653       animations: animations,
19654       android: android
19655     };
19656   }];
19657 }
19658
19659 var $templateRequestMinErr = minErr('$compile');
19660
19661 /**
19662  * @ngdoc provider
19663  * @name $templateRequestProvider
19664  * @this
19665  *
19666  * @description
19667  * Used to configure the options passed to the {@link $http} service when making a template request.
19668  *
19669  * For example, it can be used for specifying the "Accept" header that is sent to the server, when
19670  * requesting a template.
19671  */
19672 function $TemplateRequestProvider() {
19673
19674   var httpOptions;
19675
19676   /**
19677    * @ngdoc method
19678    * @name $templateRequestProvider#httpOptions
19679    * @description
19680    * The options to be passed to the {@link $http} service when making the request.
19681    * You can use this to override options such as the "Accept" header for template requests.
19682    *
19683    * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
19684    * options if not overridden here.
19685    *
19686    * @param {string=} value new value for the {@link $http} options.
19687    * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
19688    */
19689   this.httpOptions = function(val) {
19690     if (val) {
19691       httpOptions = val;
19692       return this;
19693     }
19694     return httpOptions;
19695   };
19696
19697   /**
19698    * @ngdoc service
19699    * @name $templateRequest
19700    *
19701    * @description
19702    * The `$templateRequest` service runs security checks then downloads the provided template using
19703    * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
19704    * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
19705    * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
19706    * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
19707    * when `tpl` is of type string and `$templateCache` has the matching entry.
19708    *
19709    * If you want to pass custom options to the `$http` service, such as setting the Accept header you
19710    * can configure this via {@link $templateRequestProvider#httpOptions}.
19711    *
19712    * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
19713    * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
19714    *
19715    * @return {Promise} a promise for the HTTP response data of the given URL.
19716    *
19717    * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
19718    */
19719   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
19720
19721     function handleRequestFn(tpl, ignoreRequestError) {
19722       handleRequestFn.totalPendingRequests++;
19723
19724       // We consider the template cache holds only trusted templates, so
19725       // there's no need to go through whitelisting again for keys that already
19726       // are included in there. This also makes Angular accept any script
19727       // directive, no matter its name. However, we still need to unwrap trusted
19728       // types.
19729       if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {
19730         tpl = $sce.getTrustedResourceUrl(tpl);
19731       }
19732
19733       var transformResponse = $http.defaults && $http.defaults.transformResponse;
19734
19735       if (isArray(transformResponse)) {
19736         transformResponse = transformResponse.filter(function(transformer) {
19737           return transformer !== defaultHttpResponseTransform;
19738         });
19739       } else if (transformResponse === defaultHttpResponseTransform) {
19740         transformResponse = null;
19741       }
19742
19743       return $http.get(tpl, extend({
19744           cache: $templateCache,
19745           transformResponse: transformResponse
19746         }, httpOptions)
19747         )['finally'](function() {
19748           handleRequestFn.totalPendingRequests--;
19749         })
19750         .then(function(response) {
19751           $templateCache.put(tpl, response.data);
19752           return response.data;
19753         }, handleError);
19754
19755       function handleError(resp) {
19756         if (!ignoreRequestError) {
19757           throw $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
19758             tpl, resp.status, resp.statusText);
19759         }
19760         return $q.reject(resp);
19761       }
19762     }
19763
19764     handleRequestFn.totalPendingRequests = 0;
19765
19766     return handleRequestFn;
19767   }];
19768 }
19769
19770 /** @this */
19771 function $$TestabilityProvider() {
19772   this.$get = ['$rootScope', '$browser', '$location',
19773        function($rootScope,   $browser,   $location) {
19774
19775     /**
19776      * @name $testability
19777      *
19778      * @description
19779      * The private $$testability service provides a collection of methods for use when debugging
19780      * or by automated test and debugging tools.
19781      */
19782     var testability = {};
19783
19784     /**
19785      * @name $$testability#findBindings
19786      *
19787      * @description
19788      * Returns an array of elements that are bound (via ng-bind or {{}})
19789      * to expressions matching the input.
19790      *
19791      * @param {Element} element The element root to search from.
19792      * @param {string} expression The binding expression to match.
19793      * @param {boolean} opt_exactMatch If true, only returns exact matches
19794      *     for the expression. Filters and whitespace are ignored.
19795      */
19796     testability.findBindings = function(element, expression, opt_exactMatch) {
19797       var bindings = element.getElementsByClassName('ng-binding');
19798       var matches = [];
19799       forEach(bindings, function(binding) {
19800         var dataBinding = angular.element(binding).data('$binding');
19801         if (dataBinding) {
19802           forEach(dataBinding, function(bindingName) {
19803             if (opt_exactMatch) {
19804               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
19805               if (matcher.test(bindingName)) {
19806                 matches.push(binding);
19807               }
19808             } else {
19809               if (bindingName.indexOf(expression) !== -1) {
19810                 matches.push(binding);
19811               }
19812             }
19813           });
19814         }
19815       });
19816       return matches;
19817     };
19818
19819     /**
19820      * @name $$testability#findModels
19821      *
19822      * @description
19823      * Returns an array of elements that are two-way found via ng-model to
19824      * expressions matching the input.
19825      *
19826      * @param {Element} element The element root to search from.
19827      * @param {string} expression The model expression to match.
19828      * @param {boolean} opt_exactMatch If true, only returns exact matches
19829      *     for the expression.
19830      */
19831     testability.findModels = function(element, expression, opt_exactMatch) {
19832       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
19833       for (var p = 0; p < prefixes.length; ++p) {
19834         var attributeEquals = opt_exactMatch ? '=' : '*=';
19835         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
19836         var elements = element.querySelectorAll(selector);
19837         if (elements.length) {
19838           return elements;
19839         }
19840       }
19841     };
19842
19843     /**
19844      * @name $$testability#getLocation
19845      *
19846      * @description
19847      * Shortcut for getting the location in a browser agnostic way. Returns
19848      *     the path, search, and hash. (e.g. /path?a=b#hash)
19849      */
19850     testability.getLocation = function() {
19851       return $location.url();
19852     };
19853
19854     /**
19855      * @name $$testability#setLocation
19856      *
19857      * @description
19858      * Shortcut for navigating to a location without doing a full page reload.
19859      *
19860      * @param {string} url The location url (path, search and hash,
19861      *     e.g. /path?a=b#hash) to go to.
19862      */
19863     testability.setLocation = function(url) {
19864       if (url !== $location.url()) {
19865         $location.url(url);
19866         $rootScope.$digest();
19867       }
19868     };
19869
19870     /**
19871      * @name $$testability#whenStable
19872      *
19873      * @description
19874      * Calls the callback when $timeout and $http requests are completed.
19875      *
19876      * @param {function} callback
19877      */
19878     testability.whenStable = function(callback) {
19879       $browser.notifyWhenNoOutstandingRequests(callback);
19880     };
19881
19882     return testability;
19883   }];
19884 }
19885
19886 /** @this */
19887 function $TimeoutProvider() {
19888   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
19889        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
19890
19891     var deferreds = {};
19892
19893
19894      /**
19895       * @ngdoc service
19896       * @name $timeout
19897       *
19898       * @description
19899       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
19900       * block and delegates any exceptions to
19901       * {@link ng.$exceptionHandler $exceptionHandler} service.
19902       *
19903       * The return value of calling `$timeout` is a promise, which will be resolved when
19904       * the delay has passed and the timeout function, if provided, is executed.
19905       *
19906       * To cancel a timeout request, call `$timeout.cancel(promise)`.
19907       *
19908       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
19909       * synchronously flush the queue of deferred functions.
19910       *
19911       * If you only want a promise that will be resolved after some specified delay
19912       * then you can call `$timeout` without the `fn` function.
19913       *
19914       * @param {function()=} fn A function, whose execution should be delayed.
19915       * @param {number=} [delay=0] Delay in milliseconds.
19916       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
19917       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
19918       * @param {...*=} Pass additional parameters to the executed function.
19919       * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
19920       *   will be resolved with the return value of the `fn` function.
19921       *
19922       */
19923     function timeout(fn, delay, invokeApply) {
19924       if (!isFunction(fn)) {
19925         invokeApply = delay;
19926         delay = fn;
19927         fn = noop;
19928       }
19929
19930       var args = sliceArgs(arguments, 3),
19931           skipApply = (isDefined(invokeApply) && !invokeApply),
19932           deferred = (skipApply ? $$q : $q).defer(),
19933           promise = deferred.promise,
19934           timeoutId;
19935
19936       timeoutId = $browser.defer(function() {
19937         try {
19938           deferred.resolve(fn.apply(null, args));
19939         } catch (e) {
19940           deferred.reject(e);
19941           $exceptionHandler(e);
19942         } finally {
19943           delete deferreds[promise.$$timeoutId];
19944         }
19945
19946         if (!skipApply) $rootScope.$apply();
19947       }, delay);
19948
19949       promise.$$timeoutId = timeoutId;
19950       deferreds[timeoutId] = deferred;
19951
19952       return promise;
19953     }
19954
19955
19956      /**
19957       * @ngdoc method
19958       * @name $timeout#cancel
19959       *
19960       * @description
19961       * Cancels a task associated with the `promise`. As a result of this, the promise will be
19962       * resolved with a rejection.
19963       *
19964       * @param {Promise=} promise Promise returned by the `$timeout` function.
19965       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
19966       *   canceled.
19967       */
19968     timeout.cancel = function(promise) {
19969       if (promise && promise.$$timeoutId in deferreds) {
19970         deferreds[promise.$$timeoutId].reject('canceled');
19971         delete deferreds[promise.$$timeoutId];
19972         return $browser.defer.cancel(promise.$$timeoutId);
19973       }
19974       return false;
19975     };
19976
19977     return timeout;
19978   }];
19979 }
19980
19981 // NOTE:  The usage of window and document instead of $window and $document here is
19982 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
19983 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
19984 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
19985 // doesn't know about mocked locations and resolves URLs to the real document - which is
19986 // exactly the behavior needed here.  There is little value is mocking these out for this
19987 // service.
19988 var urlParsingNode = window.document.createElement('a');
19989 var originUrl = urlResolve(window.location.href);
19990
19991
19992 /**
19993  *
19994  * Implementation Notes for non-IE browsers
19995  * ----------------------------------------
19996  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
19997  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
19998  * URL will be resolved into an absolute URL in the context of the application document.
19999  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
20000  * properties are all populated to reflect the normalized URL.  This approach has wide
20001  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
20002  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
20003  *
20004  * Implementation Notes for IE
20005  * ---------------------------
20006  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
20007  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
20008  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
20009  * work around that by performing the parsing in a 2nd step by taking a previously normalized
20010  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
20011  * properties such as protocol, hostname, port, etc.
20012  *
20013  * References:
20014  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
20015  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
20016  *   http://url.spec.whatwg.org/#urlutils
20017  *   https://github.com/angular/angular.js/pull/2902
20018  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
20019  *
20020  * @kind function
20021  * @param {string} url The URL to be parsed.
20022  * @description Normalizes and parses a URL.
20023  * @returns {object} Returns the normalized URL as a dictionary.
20024  *
20025  *   | member name   | Description    |
20026  *   |---------------|----------------|
20027  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
20028  *   | protocol      | The protocol including the trailing colon                              |
20029  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
20030  *   | search        | The search params, minus the question mark                             |
20031  *   | hash          | The hash string, minus the hash symbol
20032  *   | hostname      | The hostname
20033  *   | port          | The port, without ":"
20034  *   | pathname      | The pathname, beginning with "/"
20035  *
20036  */
20037 function urlResolve(url) {
20038   var href = url;
20039
20040   if (msie) {
20041     // Normalize before parse.  Refer Implementation Notes on why this is
20042     // done in two steps on IE.
20043     urlParsingNode.setAttribute('href', href);
20044     href = urlParsingNode.href;
20045   }
20046
20047   urlParsingNode.setAttribute('href', href);
20048
20049   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
20050   return {
20051     href: urlParsingNode.href,
20052     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
20053     host: urlParsingNode.host,
20054     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
20055     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
20056     hostname: urlParsingNode.hostname,
20057     port: urlParsingNode.port,
20058     pathname: (urlParsingNode.pathname.charAt(0) === '/')
20059       ? urlParsingNode.pathname
20060       : '/' + urlParsingNode.pathname
20061   };
20062 }
20063
20064 /**
20065  * Parse a request URL and determine whether this is a same-origin request as the application document.
20066  *
20067  * @param {string|object} requestUrl The url of the request as a string that will be resolved
20068  * or a parsed URL object.
20069  * @returns {boolean} Whether the request is for the same origin as the application document.
20070  */
20071 function urlIsSameOrigin(requestUrl) {
20072   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
20073   return (parsed.protocol === originUrl.protocol &&
20074           parsed.host === originUrl.host);
20075 }
20076
20077 /**
20078  * @ngdoc service
20079  * @name $window
20080  * @this
20081  *
20082  * @description
20083  * A reference to the browser's `window` object. While `window`
20084  * is globally available in JavaScript, it causes testability problems, because
20085  * it is a global variable. In angular we always refer to it through the
20086  * `$window` service, so it may be overridden, removed or mocked for testing.
20087  *
20088  * Expressions, like the one defined for the `ngClick` directive in the example
20089  * below, are evaluated with respect to the current scope.  Therefore, there is
20090  * no risk of inadvertently coding in a dependency on a global value in such an
20091  * expression.
20092  *
20093  * @example
20094    <example module="windowExample" name="window-service">
20095      <file name="index.html">
20096        <script>
20097          angular.module('windowExample', [])
20098            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
20099              $scope.greeting = 'Hello, World!';
20100              $scope.doGreeting = function(greeting) {
20101                $window.alert(greeting);
20102              };
20103            }]);
20104        </script>
20105        <div ng-controller="ExampleController">
20106          <input type="text" ng-model="greeting" aria-label="greeting" />
20107          <button ng-click="doGreeting(greeting)">ALERT</button>
20108        </div>
20109      </file>
20110      <file name="protractor.js" type="protractor">
20111       it('should display the greeting in the input box', function() {
20112        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
20113        // If we click the button it will block the test runner
20114        // element(':button').click();
20115       });
20116      </file>
20117    </example>
20118  */
20119 function $WindowProvider() {
20120   this.$get = valueFn(window);
20121 }
20122
20123 /**
20124  * @name $$cookieReader
20125  * @requires $document
20126  *
20127  * @description
20128  * This is a private service for reading cookies used by $http and ngCookies
20129  *
20130  * @return {Object} a key/value map of the current cookies
20131  */
20132 function $$CookieReader($document) {
20133   var rawDocument = $document[0] || {};
20134   var lastCookies = {};
20135   var lastCookieString = '';
20136
20137   function safeDecodeURIComponent(str) {
20138     try {
20139       return decodeURIComponent(str);
20140     } catch (e) {
20141       return str;
20142     }
20143   }
20144
20145   return function() {
20146     var cookieArray, cookie, i, index, name;
20147     var currentCookieString = rawDocument.cookie || '';
20148
20149     if (currentCookieString !== lastCookieString) {
20150       lastCookieString = currentCookieString;
20151       cookieArray = lastCookieString.split('; ');
20152       lastCookies = {};
20153
20154       for (i = 0; i < cookieArray.length; i++) {
20155         cookie = cookieArray[i];
20156         index = cookie.indexOf('=');
20157         if (index > 0) { //ignore nameless cookies
20158           name = safeDecodeURIComponent(cookie.substring(0, index));
20159           // the first value that is seen for a cookie is the most
20160           // specific one.  values for the same cookie name that
20161           // follow are for less specific paths.
20162           if (isUndefined(lastCookies[name])) {
20163             lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
20164           }
20165         }
20166       }
20167     }
20168     return lastCookies;
20169   };
20170 }
20171
20172 $$CookieReader.$inject = ['$document'];
20173
20174 /** @this */
20175 function $$CookieReaderProvider() {
20176   this.$get = $$CookieReader;
20177 }
20178
20179 /* global currencyFilter: true,
20180  dateFilter: true,
20181  filterFilter: true,
20182  jsonFilter: true,
20183  limitToFilter: true,
20184  lowercaseFilter: true,
20185  numberFilter: true,
20186  orderByFilter: true,
20187  uppercaseFilter: true,
20188  */
20189
20190 /**
20191  * @ngdoc provider
20192  * @name $filterProvider
20193  * @description
20194  *
20195  * Filters are just functions which transform input to an output. However filters need to be
20196  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
20197  * annotated with dependencies and is responsible for creating a filter function.
20198  *
20199  * <div class="alert alert-warning">
20200  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
20201  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
20202  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
20203  * (`myapp_subsection_filterx`).
20204  * </div>
20205  *
20206  * ```js
20207  *   // Filter registration
20208  *   function MyModule($provide, $filterProvider) {
20209  *     // create a service to demonstrate injection (not always needed)
20210  *     $provide.value('greet', function(name){
20211  *       return 'Hello ' + name + '!';
20212  *     });
20213  *
20214  *     // register a filter factory which uses the
20215  *     // greet service to demonstrate DI.
20216  *     $filterProvider.register('greet', function(greet){
20217  *       // return the filter function which uses the greet service
20218  *       // to generate salutation
20219  *       return function(text) {
20220  *         // filters need to be forgiving so check input validity
20221  *         return text && greet(text) || text;
20222  *       };
20223  *     });
20224  *   }
20225  * ```
20226  *
20227  * The filter function is registered with the `$injector` under the filter name suffix with
20228  * `Filter`.
20229  *
20230  * ```js
20231  *   it('should be the same instance', inject(
20232  *     function($filterProvider) {
20233  *       $filterProvider.register('reverse', function(){
20234  *         return ...;
20235  *       });
20236  *     },
20237  *     function($filter, reverseFilter) {
20238  *       expect($filter('reverse')).toBe(reverseFilter);
20239  *     });
20240  * ```
20241  *
20242  *
20243  * For more information about how angular filters work, and how to create your own filters, see
20244  * {@link guide/filter Filters} in the Angular Developer Guide.
20245  */
20246
20247 /**
20248  * @ngdoc service
20249  * @name $filter
20250  * @kind function
20251  * @description
20252  * Filters are used for formatting data displayed to the user.
20253  *
20254  * They can be used in view templates, controllers or services.Angular comes
20255  * with a collection of [built-in filters](api/ng/filter), but it is easy to
20256  * define your own as well.
20257  *
20258  * The general syntax in templates is as follows:
20259  *
20260  * ```html
20261  * {{ expression [| filter_name[:parameter_value] ... ] }}
20262  * ```
20263  *
20264  * @param {String} name Name of the filter function to retrieve
20265  * @return {Function} the filter function
20266  * @example
20267    <example name="$filter" module="filterExample">
20268      <file name="index.html">
20269        <div ng-controller="MainCtrl">
20270         <h3>{{ originalText }}</h3>
20271         <h3>{{ filteredText }}</h3>
20272        </div>
20273      </file>
20274
20275      <file name="script.js">
20276       angular.module('filterExample', [])
20277       .controller('MainCtrl', function($scope, $filter) {
20278         $scope.originalText = 'hello';
20279         $scope.filteredText = $filter('uppercase')($scope.originalText);
20280       });
20281      </file>
20282    </example>
20283   */
20284 $FilterProvider.$inject = ['$provide'];
20285 /** @this */
20286 function $FilterProvider($provide) {
20287   var suffix = 'Filter';
20288
20289   /**
20290    * @ngdoc method
20291    * @name $filterProvider#register
20292    * @param {string|Object} name Name of the filter function, or an object map of filters where
20293    *    the keys are the filter names and the values are the filter factories.
20294    *
20295    *    <div class="alert alert-warning">
20296    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
20297    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
20298    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
20299    *    (`myapp_subsection_filterx`).
20300    *    </div>
20301     * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
20302    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
20303    *    of the registered filter instances.
20304    */
20305   function register(name, factory) {
20306     if (isObject(name)) {
20307       var filters = {};
20308       forEach(name, function(filter, key) {
20309         filters[key] = register(key, filter);
20310       });
20311       return filters;
20312     } else {
20313       return $provide.factory(name + suffix, factory);
20314     }
20315   }
20316   this.register = register;
20317
20318   this.$get = ['$injector', function($injector) {
20319     return function(name) {
20320       return $injector.get(name + suffix);
20321     };
20322   }];
20323
20324   ////////////////////////////////////////
20325
20326   /* global
20327     currencyFilter: false,
20328     dateFilter: false,
20329     filterFilter: false,
20330     jsonFilter: false,
20331     limitToFilter: false,
20332     lowercaseFilter: false,
20333     numberFilter: false,
20334     orderByFilter: false,
20335     uppercaseFilter: false
20336   */
20337
20338   register('currency', currencyFilter);
20339   register('date', dateFilter);
20340   register('filter', filterFilter);
20341   register('json', jsonFilter);
20342   register('limitTo', limitToFilter);
20343   register('lowercase', lowercaseFilter);
20344   register('number', numberFilter);
20345   register('orderBy', orderByFilter);
20346   register('uppercase', uppercaseFilter);
20347 }
20348
20349 /**
20350  * @ngdoc filter
20351  * @name filter
20352  * @kind function
20353  *
20354  * @description
20355  * Selects a subset of items from `array` and returns it as a new array.
20356  *
20357  * @param {Array} array The source array.
20358  * @param {string|Object|function()} expression The predicate to be used for selecting items from
20359  *   `array`.
20360  *
20361  *   Can be one of:
20362  *
20363  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
20364  *     objects with string properties in `array` that match this string will be returned. This also
20365  *     applies to nested object properties.
20366  *     The predicate can be negated by prefixing the string with `!`.
20367  *
20368  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
20369  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
20370  *     which have property `name` containing "M" and property `phone` containing "1". A special
20371  *     property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
20372  *     against any property of the object or its nested object properties. That's equivalent to the
20373  *     simple substring match with a `string` as described above. The special property name can be
20374  *     overwritten, using the `anyPropertyKey` parameter.
20375  *     The predicate can be negated by prefixing the string with `!`.
20376  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
20377  *     not containing "M".
20378  *
20379  *     Note that a named property will match properties on the same level only, while the special
20380  *     `$` property will match properties on the same level or deeper. E.g. an array item like
20381  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
20382  *     **will** be matched by `{$: 'John'}`.
20383  *
20384  *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
20385  *     The function is called for each element of the array, with the element, its index, and
20386  *     the entire array itself as arguments.
20387  *
20388  *     The final result is an array of those elements that the predicate returned true for.
20389  *
20390  * @param {function(actual, expected)|true|false} [comparator] Comparator which is used in
20391  *     determining if the expected value (from the filter expression) and actual value (from
20392  *     the object in the array) should be considered a match.
20393  *
20394  *   Can be one of:
20395  *
20396  *   - `function(actual, expected)`:
20397  *     The function will be given the object value and the predicate value to compare and
20398  *     should return true if both values should be considered equal.
20399  *
20400  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
20401  *     This is essentially strict comparison of expected and actual.
20402  *
20403  *   - `false`: A short hand for a function which will look for a substring match in a case
20404  *     insensitive way. Primitive values are converted to strings. Objects are not compared against
20405  *     primitives, unless they have a custom `toString` method (e.g. `Date` objects).
20406  *
20407  *
20408  *   Defaults to `false`.
20409  *
20410  * @param {string} [anyPropertyKey] The special property name that matches against any property.
20411  *     By default `$`.
20412  *
20413  * @example
20414    <example name="filter-filter">
20415      <file name="index.html">
20416        <div ng-init="friends = [{name:'John', phone:'555-1276'},
20417                                 {name:'Mary', phone:'800-BIG-MARY'},
20418                                 {name:'Mike', phone:'555-4321'},
20419                                 {name:'Adam', phone:'555-5678'},
20420                                 {name:'Julie', phone:'555-8765'},
20421                                 {name:'Juliette', phone:'555-5678'}]"></div>
20422
20423        <label>Search: <input ng-model="searchText"></label>
20424        <table id="searchTextResults">
20425          <tr><th>Name</th><th>Phone</th></tr>
20426          <tr ng-repeat="friend in friends | filter:searchText">
20427            <td>{{friend.name}}</td>
20428            <td>{{friend.phone}}</td>
20429          </tr>
20430        </table>
20431        <hr>
20432        <label>Any: <input ng-model="search.$"></label> <br>
20433        <label>Name only <input ng-model="search.name"></label><br>
20434        <label>Phone only <input ng-model="search.phone"></label><br>
20435        <label>Equality <input type="checkbox" ng-model="strict"></label><br>
20436        <table id="searchObjResults">
20437          <tr><th>Name</th><th>Phone</th></tr>
20438          <tr ng-repeat="friendObj in friends | filter:search:strict">
20439            <td>{{friendObj.name}}</td>
20440            <td>{{friendObj.phone}}</td>
20441          </tr>
20442        </table>
20443      </file>
20444      <file name="protractor.js" type="protractor">
20445        var expectFriendNames = function(expectedNames, key) {
20446          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
20447            arr.forEach(function(wd, i) {
20448              expect(wd.getText()).toMatch(expectedNames[i]);
20449            });
20450          });
20451        };
20452
20453        it('should search across all fields when filtering with a string', function() {
20454          var searchText = element(by.model('searchText'));
20455          searchText.clear();
20456          searchText.sendKeys('m');
20457          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
20458
20459          searchText.clear();
20460          searchText.sendKeys('76');
20461          expectFriendNames(['John', 'Julie'], 'friend');
20462        });
20463
20464        it('should search in specific fields when filtering with a predicate object', function() {
20465          var searchAny = element(by.model('search.$'));
20466          searchAny.clear();
20467          searchAny.sendKeys('i');
20468          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
20469        });
20470        it('should use a equal comparison when comparator is true', function() {
20471          var searchName = element(by.model('search.name'));
20472          var strict = element(by.model('strict'));
20473          searchName.clear();
20474          searchName.sendKeys('Julie');
20475          strict.click();
20476          expectFriendNames(['Julie'], 'friendObj');
20477        });
20478      </file>
20479    </example>
20480  */
20481
20482 function filterFilter() {
20483   return function(array, expression, comparator, anyPropertyKey) {
20484     if (!isArrayLike(array)) {
20485       if (array == null) {
20486         return array;
20487       } else {
20488         throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
20489       }
20490     }
20491
20492     anyPropertyKey = anyPropertyKey || '$';
20493     var expressionType = getTypeForFilter(expression);
20494     var predicateFn;
20495     var matchAgainstAnyProp;
20496
20497     switch (expressionType) {
20498       case 'function':
20499         predicateFn = expression;
20500         break;
20501       case 'boolean':
20502       case 'null':
20503       case 'number':
20504       case 'string':
20505         matchAgainstAnyProp = true;
20506         // falls through
20507       case 'object':
20508         predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);
20509         break;
20510       default:
20511         return array;
20512     }
20513
20514     return Array.prototype.filter.call(array, predicateFn);
20515   };
20516 }
20517
20518 // Helper functions for `filterFilter`
20519 function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {
20520   var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);
20521   var predicateFn;
20522
20523   if (comparator === true) {
20524     comparator = equals;
20525   } else if (!isFunction(comparator)) {
20526     comparator = function(actual, expected) {
20527       if (isUndefined(actual)) {
20528         // No substring matching against `undefined`
20529         return false;
20530       }
20531       if ((actual === null) || (expected === null)) {
20532         // No substring matching against `null`; only match against `null`
20533         return actual === expected;
20534       }
20535       if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
20536         // Should not compare primitives against objects, unless they have custom `toString` method
20537         return false;
20538       }
20539
20540       actual = lowercase('' + actual);
20541       expected = lowercase('' + expected);
20542       return actual.indexOf(expected) !== -1;
20543     };
20544   }
20545
20546   predicateFn = function(item) {
20547     if (shouldMatchPrimitives && !isObject(item)) {
20548       return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);
20549     }
20550     return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);
20551   };
20552
20553   return predicateFn;
20554 }
20555
20556 function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {
20557   var actualType = getTypeForFilter(actual);
20558   var expectedType = getTypeForFilter(expected);
20559
20560   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
20561     return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);
20562   } else if (isArray(actual)) {
20563     // In case `actual` is an array, consider it a match
20564     // if ANY of it's items matches `expected`
20565     return actual.some(function(item) {
20566       return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);
20567     });
20568   }
20569
20570   switch (actualType) {
20571     case 'object':
20572       var key;
20573       if (matchAgainstAnyProp) {
20574         for (key in actual) {
20575           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
20576             return true;
20577           }
20578         }
20579         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);
20580       } else if (expectedType === 'object') {
20581         for (key in expected) {
20582           var expectedVal = expected[key];
20583           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
20584             continue;
20585           }
20586
20587           var matchAnyProperty = key === anyPropertyKey;
20588           var actualVal = matchAnyProperty ? actual : actual[key];
20589           if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {
20590             return false;
20591           }
20592         }
20593         return true;
20594       } else {
20595         return comparator(actual, expected);
20596       }
20597     case 'function':
20598       return false;
20599     default:
20600       return comparator(actual, expected);
20601   }
20602 }
20603
20604 // Used for easily differentiating between `null` and actual `object`
20605 function getTypeForFilter(val) {
20606   return (val === null) ? 'null' : typeof val;
20607 }
20608
20609 var MAX_DIGITS = 22;
20610 var DECIMAL_SEP = '.';
20611 var ZERO_CHAR = '0';
20612
20613 /**
20614  * @ngdoc filter
20615  * @name currency
20616  * @kind function
20617  *
20618  * @description
20619  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
20620  * symbol for current locale is used.
20621  *
20622  * @param {number} amount Input to filter.
20623  * @param {string=} symbol Currency symbol or identifier to be displayed.
20624  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
20625  * @returns {string} Formatted number.
20626  *
20627  *
20628  * @example
20629    <example module="currencyExample" name="currency-filter">
20630      <file name="index.html">
20631        <script>
20632          angular.module('currencyExample', [])
20633            .controller('ExampleController', ['$scope', function($scope) {
20634              $scope.amount = 1234.56;
20635            }]);
20636        </script>
20637        <div ng-controller="ExampleController">
20638          <input type="number" ng-model="amount" aria-label="amount"> <br>
20639          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
20640          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
20641          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
20642        </div>
20643      </file>
20644      <file name="protractor.js" type="protractor">
20645        it('should init with 1234.56', function() {
20646          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
20647          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
20648          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
20649        });
20650        it('should update', function() {
20651          if (browser.params.browser === 'safari') {
20652            // Safari does not understand the minus key. See
20653            // https://github.com/angular/protractor/issues/481
20654            return;
20655          }
20656          element(by.model('amount')).clear();
20657          element(by.model('amount')).sendKeys('-1234');
20658          expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
20659          expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
20660          expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
20661        });
20662      </file>
20663    </example>
20664  */
20665 currencyFilter.$inject = ['$locale'];
20666 function currencyFilter($locale) {
20667   var formats = $locale.NUMBER_FORMATS;
20668   return function(amount, currencySymbol, fractionSize) {
20669     if (isUndefined(currencySymbol)) {
20670       currencySymbol = formats.CURRENCY_SYM;
20671     }
20672
20673     if (isUndefined(fractionSize)) {
20674       fractionSize = formats.PATTERNS[1].maxFrac;
20675     }
20676
20677     // if null or undefined pass it through
20678     return (amount == null)
20679         ? amount
20680         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
20681             replace(/\u00A4/g, currencySymbol);
20682   };
20683 }
20684
20685 /**
20686  * @ngdoc filter
20687  * @name number
20688  * @kind function
20689  *
20690  * @description
20691  * Formats a number as text.
20692  *
20693  * If the input is null or undefined, it will just be returned.
20694  * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
20695  * If the input is not a number an empty string is returned.
20696  *
20697  *
20698  * @param {number|string} number Number to format.
20699  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
20700  * If this is not provided then the fraction size is computed from the current locale's number
20701  * formatting pattern. In the case of the default locale, it will be 3.
20702  * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
20703  *                   locale (e.g., in the en_US locale it will have "." as the decimal separator and
20704  *                   include "," group separators after each third digit).
20705  *
20706  * @example
20707    <example module="numberFilterExample" name="number-filter">
20708      <file name="index.html">
20709        <script>
20710          angular.module('numberFilterExample', [])
20711            .controller('ExampleController', ['$scope', function($scope) {
20712              $scope.val = 1234.56789;
20713            }]);
20714        </script>
20715        <div ng-controller="ExampleController">
20716          <label>Enter number: <input ng-model='val'></label><br>
20717          Default formatting: <span id='number-default'>{{val | number}}</span><br>
20718          No fractions: <span>{{val | number:0}}</span><br>
20719          Negative number: <span>{{-val | number:4}}</span>
20720        </div>
20721      </file>
20722      <file name="protractor.js" type="protractor">
20723        it('should format numbers', function() {
20724          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
20725          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
20726          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
20727        });
20728
20729        it('should update', function() {
20730          element(by.model('val')).clear();
20731          element(by.model('val')).sendKeys('3374.333');
20732          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
20733          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
20734          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
20735       });
20736      </file>
20737    </example>
20738  */
20739 numberFilter.$inject = ['$locale'];
20740 function numberFilter($locale) {
20741   var formats = $locale.NUMBER_FORMATS;
20742   return function(number, fractionSize) {
20743
20744     // if null or undefined pass it through
20745     return (number == null)
20746         ? number
20747         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
20748                        fractionSize);
20749   };
20750 }
20751
20752 /**
20753  * Parse a number (as a string) into three components that can be used
20754  * for formatting the number.
20755  *
20756  * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
20757  *
20758  * @param  {string} numStr The number to parse
20759  * @return {object} An object describing this number, containing the following keys:
20760  *  - d : an array of digits containing leading zeros as necessary
20761  *  - i : the number of the digits in `d` that are to the left of the decimal point
20762  *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
20763  *
20764  */
20765 function parse(numStr) {
20766   var exponent = 0, digits, numberOfIntegerDigits;
20767   var i, j, zeros;
20768
20769   // Decimal point?
20770   if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
20771     numStr = numStr.replace(DECIMAL_SEP, '');
20772   }
20773
20774   // Exponential form?
20775   if ((i = numStr.search(/e/i)) > 0) {
20776     // Work out the exponent.
20777     if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
20778     numberOfIntegerDigits += +numStr.slice(i + 1);
20779     numStr = numStr.substring(0, i);
20780   } else if (numberOfIntegerDigits < 0) {
20781     // There was no decimal point or exponent so it is an integer.
20782     numberOfIntegerDigits = numStr.length;
20783   }
20784
20785   // Count the number of leading zeros.
20786   for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { /* empty */ }
20787
20788   if (i === (zeros = numStr.length)) {
20789     // The digits are all zero.
20790     digits = [0];
20791     numberOfIntegerDigits = 1;
20792   } else {
20793     // Count the number of trailing zeros
20794     zeros--;
20795     while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;
20796
20797     // Trailing zeros are insignificant so ignore them
20798     numberOfIntegerDigits -= i;
20799     digits = [];
20800     // Convert string to array of digits without leading/trailing zeros.
20801     for (j = 0; i <= zeros; i++, j++) {
20802       digits[j] = +numStr.charAt(i);
20803     }
20804   }
20805
20806   // If the number overflows the maximum allowed digits then use an exponent.
20807   if (numberOfIntegerDigits > MAX_DIGITS) {
20808     digits = digits.splice(0, MAX_DIGITS - 1);
20809     exponent = numberOfIntegerDigits - 1;
20810     numberOfIntegerDigits = 1;
20811   }
20812
20813   return { d: digits, e: exponent, i: numberOfIntegerDigits };
20814 }
20815
20816 /**
20817  * Round the parsed number to the specified number of decimal places
20818  * This function changed the parsedNumber in-place
20819  */
20820 function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
20821     var digits = parsedNumber.d;
20822     var fractionLen = digits.length - parsedNumber.i;
20823
20824     // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
20825     fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
20826
20827     // The index of the digit to where rounding is to occur
20828     var roundAt = fractionSize + parsedNumber.i;
20829     var digit = digits[roundAt];
20830
20831     if (roundAt > 0) {
20832       // Drop fractional digits beyond `roundAt`
20833       digits.splice(Math.max(parsedNumber.i, roundAt));
20834
20835       // Set non-fractional digits beyond `roundAt` to 0
20836       for (var j = roundAt; j < digits.length; j++) {
20837         digits[j] = 0;
20838       }
20839     } else {
20840       // We rounded to zero so reset the parsedNumber
20841       fractionLen = Math.max(0, fractionLen);
20842       parsedNumber.i = 1;
20843       digits.length = Math.max(1, roundAt = fractionSize + 1);
20844       digits[0] = 0;
20845       for (var i = 1; i < roundAt; i++) digits[i] = 0;
20846     }
20847
20848     if (digit >= 5) {
20849       if (roundAt - 1 < 0) {
20850         for (var k = 0; k > roundAt; k--) {
20851           digits.unshift(0);
20852           parsedNumber.i++;
20853         }
20854         digits.unshift(1);
20855         parsedNumber.i++;
20856       } else {
20857         digits[roundAt - 1]++;
20858       }
20859     }
20860
20861     // Pad out with zeros to get the required fraction length
20862     for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
20863
20864
20865     // Do any carrying, e.g. a digit was rounded up to 10
20866     var carry = digits.reduceRight(function(carry, d, i, digits) {
20867       d = d + carry;
20868       digits[i] = d % 10;
20869       return Math.floor(d / 10);
20870     }, 0);
20871     if (carry) {
20872       digits.unshift(carry);
20873       parsedNumber.i++;
20874     }
20875 }
20876
20877 /**
20878  * Format a number into a string
20879  * @param  {number} number       The number to format
20880  * @param  {{
20881  *           minFrac, // the minimum number of digits required in the fraction part of the number
20882  *           maxFrac, // the maximum number of digits required in the fraction part of the number
20883  *           gSize,   // number of digits in each group of separated digits
20884  *           lgSize,  // number of digits in the last group of digits before the decimal separator
20885  *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
20886  *           posPre,  // the string to go in front of a positive number
20887  *           negSuf,  // the string to go after a negative number (e.g. `)`)
20888  *           posSuf   // the string to go after a positive number
20889  *         }} pattern
20890  * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
20891  * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
20892  * @param  {[type]} fractionSize The size of the fractional part of the number
20893  * @return {string}              The number formatted as a string
20894  */
20895 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
20896
20897   if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
20898
20899   var isInfinity = !isFinite(number);
20900   var isZero = false;
20901   var numStr = Math.abs(number) + '',
20902       formattedText = '',
20903       parsedNumber;
20904
20905   if (isInfinity) {
20906     formattedText = '\u221e';
20907   } else {
20908     parsedNumber = parse(numStr);
20909
20910     roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
20911
20912     var digits = parsedNumber.d;
20913     var integerLen = parsedNumber.i;
20914     var exponent = parsedNumber.e;
20915     var decimals = [];
20916     isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
20917
20918     // pad zeros for small numbers
20919     while (integerLen < 0) {
20920       digits.unshift(0);
20921       integerLen++;
20922     }
20923
20924     // extract decimals digits
20925     if (integerLen > 0) {
20926       decimals = digits.splice(integerLen, digits.length);
20927     } else {
20928       decimals = digits;
20929       digits = [0];
20930     }
20931
20932     // format the integer digits with grouping separators
20933     var groups = [];
20934     if (digits.length >= pattern.lgSize) {
20935       groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
20936     }
20937     while (digits.length > pattern.gSize) {
20938       groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
20939     }
20940     if (digits.length) {
20941       groups.unshift(digits.join(''));
20942     }
20943     formattedText = groups.join(groupSep);
20944
20945     // append the decimal digits
20946     if (decimals.length) {
20947       formattedText += decimalSep + decimals.join('');
20948     }
20949
20950     if (exponent) {
20951       formattedText += 'e+' + exponent;
20952     }
20953   }
20954   if (number < 0 && !isZero) {
20955     return pattern.negPre + formattedText + pattern.negSuf;
20956   } else {
20957     return pattern.posPre + formattedText + pattern.posSuf;
20958   }
20959 }
20960
20961 function padNumber(num, digits, trim, negWrap) {
20962   var neg = '';
20963   if (num < 0 || (negWrap && num <= 0)) {
20964     if (negWrap) {
20965       num = -num + 1;
20966     } else {
20967       num = -num;
20968       neg = '-';
20969     }
20970   }
20971   num = '' + num;
20972   while (num.length < digits) num = ZERO_CHAR + num;
20973   if (trim) {
20974     num = num.substr(num.length - digits);
20975   }
20976   return neg + num;
20977 }
20978
20979
20980 function dateGetter(name, size, offset, trim, negWrap) {
20981   offset = offset || 0;
20982   return function(date) {
20983     var value = date['get' + name]();
20984     if (offset > 0 || value > -offset) {
20985       value += offset;
20986     }
20987     if (value === 0 && offset === -12) value = 12;
20988     return padNumber(value, size, trim, negWrap);
20989   };
20990 }
20991
20992 function dateStrGetter(name, shortForm, standAlone) {
20993   return function(date, formats) {
20994     var value = date['get' + name]();
20995     var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
20996     var get = uppercase(propPrefix + name);
20997
20998     return formats[get][value];
20999   };
21000 }
21001
21002 function timeZoneGetter(date, formats, offset) {
21003   var zone = -1 * offset;
21004   var paddedZone = (zone >= 0) ? '+' : '';
21005
21006   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
21007                 padNumber(Math.abs(zone % 60), 2);
21008
21009   return paddedZone;
21010 }
21011
21012 function getFirstThursdayOfYear(year) {
21013     // 0 = index of January
21014     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
21015     // 4 = index of Thursday (+1 to account for 1st = 5)
21016     // 11 = index of *next* Thursday (+1 account for 1st = 12)
21017     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
21018 }
21019
21020 function getThursdayThisWeek(datetime) {
21021     return new Date(datetime.getFullYear(), datetime.getMonth(),
21022       // 4 = index of Thursday
21023       datetime.getDate() + (4 - datetime.getDay()));
21024 }
21025
21026 function weekGetter(size) {
21027    return function(date) {
21028       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
21029          thisThurs = getThursdayThisWeek(date);
21030
21031       var diff = +thisThurs - +firstThurs,
21032          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
21033
21034       return padNumber(result, size);
21035    };
21036 }
21037
21038 function ampmGetter(date, formats) {
21039   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
21040 }
21041
21042 function eraGetter(date, formats) {
21043   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
21044 }
21045
21046 function longEraGetter(date, formats) {
21047   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
21048 }
21049
21050 var DATE_FORMATS = {
21051   yyyy: dateGetter('FullYear', 4, 0, false, true),
21052     yy: dateGetter('FullYear', 2, 0, true, true),
21053      y: dateGetter('FullYear', 1, 0, false, true),
21054   MMMM: dateStrGetter('Month'),
21055    MMM: dateStrGetter('Month', true),
21056     MM: dateGetter('Month', 2, 1),
21057      M: dateGetter('Month', 1, 1),
21058   LLLL: dateStrGetter('Month', false, true),
21059     dd: dateGetter('Date', 2),
21060      d: dateGetter('Date', 1),
21061     HH: dateGetter('Hours', 2),
21062      H: dateGetter('Hours', 1),
21063     hh: dateGetter('Hours', 2, -12),
21064      h: dateGetter('Hours', 1, -12),
21065     mm: dateGetter('Minutes', 2),
21066      m: dateGetter('Minutes', 1),
21067     ss: dateGetter('Seconds', 2),
21068      s: dateGetter('Seconds', 1),
21069      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
21070      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
21071    sss: dateGetter('Milliseconds', 3),
21072   EEEE: dateStrGetter('Day'),
21073    EEE: dateStrGetter('Day', true),
21074      a: ampmGetter,
21075      Z: timeZoneGetter,
21076     ww: weekGetter(2),
21077      w: weekGetter(1),
21078      G: eraGetter,
21079      GG: eraGetter,
21080      GGG: eraGetter,
21081      GGGG: longEraGetter
21082 };
21083
21084 var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
21085     NUMBER_STRING = /^-?\d+$/;
21086
21087 /**
21088  * @ngdoc filter
21089  * @name date
21090  * @kind function
21091  *
21092  * @description
21093  *   Formats `date` to a string based on the requested `format`.
21094  *
21095  *   `format` string can be composed of the following elements:
21096  *
21097  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
21098  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
21099  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
21100  *   * `'MMMM'`: Month in year (January-December)
21101  *   * `'MMM'`: Month in year (Jan-Dec)
21102  *   * `'MM'`: Month in year, padded (01-12)
21103  *   * `'M'`: Month in year (1-12)
21104  *   * `'LLLL'`: Stand-alone month in year (January-December)
21105  *   * `'dd'`: Day in month, padded (01-31)
21106  *   * `'d'`: Day in month (1-31)
21107  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
21108  *   * `'EEE'`: Day in Week, (Sun-Sat)
21109  *   * `'HH'`: Hour in day, padded (00-23)
21110  *   * `'H'`: Hour in day (0-23)
21111  *   * `'hh'`: Hour in AM/PM, padded (01-12)
21112  *   * `'h'`: Hour in AM/PM, (1-12)
21113  *   * `'mm'`: Minute in hour, padded (00-59)
21114  *   * `'m'`: Minute in hour (0-59)
21115  *   * `'ss'`: Second in minute, padded (00-59)
21116  *   * `'s'`: Second in minute (0-59)
21117  *   * `'sss'`: Millisecond in second, padded (000-999)
21118  *   * `'a'`: AM/PM marker
21119  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
21120  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
21121  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
21122  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
21123  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
21124  *
21125  *   `format` string can also be one of the following predefined
21126  *   {@link guide/i18n localizable formats}:
21127  *
21128  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
21129  *     (e.g. Sep 3, 2010 12:05:08 PM)
21130  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
21131  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
21132  *     (e.g. Friday, September 3, 2010)
21133  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
21134  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
21135  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
21136  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
21137  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
21138  *
21139  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
21140  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
21141  *   (e.g. `"h 'o''clock'"`).
21142  *
21143  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
21144  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
21145  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
21146  *    specified in the string input, the time is considered to be in the local timezone.
21147  * @param {string=} format Formatting rules (see Description). If not specified,
21148  *    `mediumDate` is used.
21149  * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
21150  *    continental US time zone abbreviations, but for general use, use a time zone offset, for
21151  *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
21152  *    If not specified, the timezone of the browser will be used.
21153  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
21154  *
21155  * @example
21156    <example name="filter-date">
21157      <file name="index.html">
21158        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
21159            <span>{{1288323623006 | date:'medium'}}</span><br>
21160        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
21161           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
21162        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
21163           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
21164        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
21165           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
21166      </file>
21167      <file name="protractor.js" type="protractor">
21168        it('should format date', function() {
21169          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
21170             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
21171          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
21172             toMatch(/2010-10-2\d \d{2}:\d{2}:\d{2} (-|\+)?\d{4}/);
21173          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
21174             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
21175          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
21176             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
21177        });
21178      </file>
21179    </example>
21180  */
21181 dateFilter.$inject = ['$locale'];
21182 function dateFilter($locale) {
21183
21184
21185   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
21186                      // 1        2       3         4          5          6          7          8  9     10      11
21187   function jsonStringToDate(string) {
21188     var match;
21189     if ((match = string.match(R_ISO8601_STR))) {
21190       var date = new Date(0),
21191           tzHour = 0,
21192           tzMin  = 0,
21193           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
21194           timeSetter = match[8] ? date.setUTCHours : date.setHours;
21195
21196       if (match[9]) {
21197         tzHour = toInt(match[9] + match[10]);
21198         tzMin = toInt(match[9] + match[11]);
21199       }
21200       dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
21201       var h = toInt(match[4] || 0) - tzHour;
21202       var m = toInt(match[5] || 0) - tzMin;
21203       var s = toInt(match[6] || 0);
21204       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
21205       timeSetter.call(date, h, m, s, ms);
21206       return date;
21207     }
21208     return string;
21209   }
21210
21211
21212   return function(date, format, timezone) {
21213     var text = '',
21214         parts = [],
21215         fn, match;
21216
21217     format = format || 'mediumDate';
21218     format = $locale.DATETIME_FORMATS[format] || format;
21219     if (isString(date)) {
21220       date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
21221     }
21222
21223     if (isNumber(date)) {
21224       date = new Date(date);
21225     }
21226
21227     if (!isDate(date) || !isFinite(date.getTime())) {
21228       return date;
21229     }
21230
21231     while (format) {
21232       match = DATE_FORMATS_SPLIT.exec(format);
21233       if (match) {
21234         parts = concat(parts, match, 1);
21235         format = parts.pop();
21236       } else {
21237         parts.push(format);
21238         format = null;
21239       }
21240     }
21241
21242     var dateTimezoneOffset = date.getTimezoneOffset();
21243     if (timezone) {
21244       dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
21245       date = convertTimezoneToLocal(date, timezone, true);
21246     }
21247     forEach(parts, function(value) {
21248       fn = DATE_FORMATS[value];
21249       text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
21250                  : value === '\'\'' ? '\'' : value.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
21251     });
21252
21253     return text;
21254   };
21255 }
21256
21257
21258 /**
21259  * @ngdoc filter
21260  * @name json
21261  * @kind function
21262  *
21263  * @description
21264  *   Allows you to convert a JavaScript object into JSON string.
21265  *
21266  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
21267  *   the binding is automatically converted to JSON.
21268  *
21269  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
21270  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
21271  * @returns {string} JSON string.
21272  *
21273  *
21274  * @example
21275    <example name="filter-json">
21276      <file name="index.html">
21277        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
21278        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
21279      </file>
21280      <file name="protractor.js" type="protractor">
21281        it('should jsonify filtered objects', function() {
21282          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n {2}"name": ?"value"\n}/);
21283          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n {4}"name": ?"value"\n}/);
21284        });
21285      </file>
21286    </example>
21287  *
21288  */
21289 function jsonFilter() {
21290   return function(object, spacing) {
21291     if (isUndefined(spacing)) {
21292         spacing = 2;
21293     }
21294     return toJson(object, spacing);
21295   };
21296 }
21297
21298
21299 /**
21300  * @ngdoc filter
21301  * @name lowercase
21302  * @kind function
21303  * @description
21304  * Converts string to lowercase.
21305  * @see angular.lowercase
21306  */
21307 var lowercaseFilter = valueFn(lowercase);
21308
21309
21310 /**
21311  * @ngdoc filter
21312  * @name uppercase
21313  * @kind function
21314  * @description
21315  * Converts string to uppercase.
21316  * @see angular.uppercase
21317  */
21318 var uppercaseFilter = valueFn(uppercase);
21319
21320 /**
21321  * @ngdoc filter
21322  * @name limitTo
21323  * @kind function
21324  *
21325  * @description
21326  * Creates a new array or string containing only a specified number of elements. The elements are
21327  * taken from either the beginning or the end of the source array, string or number, as specified by
21328  * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
21329  * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
21330  * it is converted to a string.
21331  *
21332  * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
21333  * @param {string|number} limit - The length of the returned array or string. If the `limit` number
21334  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
21335  *     If the number is negative, `limit` number  of items from the end of the source array/string
21336  *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
21337  *     the input will be returned unchanged.
21338  * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
21339  *     `begin` indicates an offset from the end of `input`. Defaults to `0`.
21340  * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
21341  *     less than `limit` elements.
21342  *
21343  * @example
21344    <example module="limitToExample" name="limit-to-filter">
21345      <file name="index.html">
21346        <script>
21347          angular.module('limitToExample', [])
21348            .controller('ExampleController', ['$scope', function($scope) {
21349              $scope.numbers = [1,2,3,4,5,6,7,8,9];
21350              $scope.letters = "abcdefghi";
21351              $scope.longNumber = 2345432342;
21352              $scope.numLimit = 3;
21353              $scope.letterLimit = 3;
21354              $scope.longNumberLimit = 3;
21355            }]);
21356        </script>
21357        <div ng-controller="ExampleController">
21358          <label>
21359             Limit {{numbers}} to:
21360             <input type="number" step="1" ng-model="numLimit">
21361          </label>
21362          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
21363          <label>
21364             Limit {{letters}} to:
21365             <input type="number" step="1" ng-model="letterLimit">
21366          </label>
21367          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
21368          <label>
21369             Limit {{longNumber}} to:
21370             <input type="number" step="1" ng-model="longNumberLimit">
21371          </label>
21372          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
21373        </div>
21374      </file>
21375      <file name="protractor.js" type="protractor">
21376        var numLimitInput = element(by.model('numLimit'));
21377        var letterLimitInput = element(by.model('letterLimit'));
21378        var longNumberLimitInput = element(by.model('longNumberLimit'));
21379        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
21380        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
21381        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
21382
21383        it('should limit the number array to first three items', function() {
21384          expect(numLimitInput.getAttribute('value')).toBe('3');
21385          expect(letterLimitInput.getAttribute('value')).toBe('3');
21386          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
21387          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
21388          expect(limitedLetters.getText()).toEqual('Output letters: abc');
21389          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
21390        });
21391
21392        // There is a bug in safari and protractor that doesn't like the minus key
21393        // it('should update the output when -3 is entered', function() {
21394        //   numLimitInput.clear();
21395        //   numLimitInput.sendKeys('-3');
21396        //   letterLimitInput.clear();
21397        //   letterLimitInput.sendKeys('-3');
21398        //   longNumberLimitInput.clear();
21399        //   longNumberLimitInput.sendKeys('-3');
21400        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
21401        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
21402        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
21403        // });
21404
21405        it('should not exceed the maximum size of input array', function() {
21406          numLimitInput.clear();
21407          numLimitInput.sendKeys('100');
21408          letterLimitInput.clear();
21409          letterLimitInput.sendKeys('100');
21410          longNumberLimitInput.clear();
21411          longNumberLimitInput.sendKeys('100');
21412          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
21413          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
21414          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
21415        });
21416      </file>
21417    </example>
21418 */
21419 function limitToFilter() {
21420   return function(input, limit, begin) {
21421     if (Math.abs(Number(limit)) === Infinity) {
21422       limit = Number(limit);
21423     } else {
21424       limit = toInt(limit);
21425     }
21426     if (isNumberNaN(limit)) return input;
21427
21428     if (isNumber(input)) input = input.toString();
21429     if (!isArrayLike(input)) return input;
21430
21431     begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
21432     begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
21433
21434     if (limit >= 0) {
21435       return sliceFn(input, begin, begin + limit);
21436     } else {
21437       if (begin === 0) {
21438         return sliceFn(input, limit, input.length);
21439       } else {
21440         return sliceFn(input, Math.max(0, begin + limit), begin);
21441       }
21442     }
21443   };
21444 }
21445
21446 function sliceFn(input, begin, end) {
21447   if (isString(input)) return input.slice(begin, end);
21448
21449   return slice.call(input, begin, end);
21450 }
21451
21452 /**
21453  * @ngdoc filter
21454  * @name orderBy
21455  * @kind function
21456  *
21457  * @description
21458  * Returns an array containing the items from the specified `collection`, ordered by a `comparator`
21459  * function based on the values computed using the `expression` predicate.
21460  *
21461  * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in
21462  * `[{id: 'bar'}, {id: 'foo'}]`.
21463  *
21464  * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,
21465  * String, etc).
21466  *
21467  * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker
21468  * for the preceding one. The `expression` is evaluated against each item and the output is used
21469  * for comparing with other items.
21470  *
21471  * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in
21472  * ascending order.
21473  *
21474  * The comparison is done using the `comparator` function. If none is specified, a default, built-in
21475  * comparator is used (see below for details - in a nutshell, it compares numbers numerically and
21476  * strings alphabetically).
21477  *
21478  * ### Under the hood
21479  *
21480  * Ordering the specified `collection` happens in two phases:
21481  *
21482  * 1. All items are passed through the predicate (or predicates), and the returned values are saved
21483  *    along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed
21484  *    through a predicate that extracts the value of the `label` property, would be transformed to:
21485  *    ```
21486  *    {
21487  *      value: 'foo',
21488  *      type: 'string',
21489  *      index: ...
21490  *    }
21491  *    ```
21492  * 2. The comparator function is used to sort the items, based on the derived values, types and
21493  *    indices.
21494  *
21495  * If you use a custom comparator, it will be called with pairs of objects of the form
21496  * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal
21497  * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the
21498  * second, or `1` otherwise.
21499  *
21500  * In order to ensure that the sorting will be deterministic across platforms, if none of the
21501  * specified predicates can distinguish between two items, `orderBy` will automatically introduce a
21502  * dummy predicate that returns the item's index as `value`.
21503  * (If you are using a custom comparator, make sure it can handle this predicate as well.)
21504  *
21505  * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
21506  * value for an item, `orderBy` will try to convert that object to a primitive value, before passing
21507  * it to the comparator. The following rules govern the conversion:
21508  *
21509  * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be
21510  *    used instead.<br />
21511  *    (If the object has a `valueOf()` method that returns another object, then the returned object
21512  *    will be used in subsequent steps.)
21513  * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that
21514  *    returns a primitive, its return value will be used instead.<br />
21515  *    (If the object has a `toString()` method that returns another object, then the returned object
21516  *    will be used in subsequent steps.)
21517  * 3. No conversion; the object itself is used.
21518  *
21519  * ### The default comparator
21520  *
21521  * The default, built-in comparator should be sufficient for most usecases. In short, it compares
21522  * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
21523  * using their index in the original collection, and sorts values of different types by type.
21524  *
21525  * More specifically, it follows these steps to determine the relative order of items:
21526  *
21527  * 1. If the compared values are of different types, compare the types themselves alphabetically.
21528  * 2. If both values are of type `string`, compare them alphabetically in a case- and
21529  *    locale-insensitive way.
21530  * 3. If both values are objects, compare their indices instead.
21531  * 4. Otherwise, return:
21532  *    -  `0`, if the values are equal (by strict equality comparison, i.e. using `===`).
21533  *    - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator).
21534  *    -  `1`, otherwise.
21535  *
21536  * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being
21537  *           saved as numbers and not strings.
21538  * **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e.
21539  *           `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to
21540  *           other values.
21541  *
21542  * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.
21543  * @param {(Function|string|Array.<Function|string>)=} expression - A predicate (or list of
21544  *    predicates) to be used by the comparator to determine the order of elements.
21545  *
21546  *    Can be one of:
21547  *
21548  *    - `Function`: A getter function. This function will be called with each item as argument and
21549  *      the return value will be used for sorting.
21550  *    - `string`: An Angular expression. This expression will be evaluated against each item and the
21551  *      result will be used for sorting. For example, use `'label'` to sort by a property called
21552  *      `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`
21553  *      property.<br />
21554  *      (The result of a constant expression is interpreted as a property name to be used for
21555  *      comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a
21556  *      property called `special name`.)<br />
21557  *      An expression can be optionally prefixed with `+` or `-` to control the sorting direction,
21558  *      ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,
21559  *      (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.
21560  *    - `Array`: An array of function and/or string predicates. If a predicate cannot determine the
21561  *      relative order of two items, the next predicate is used as a tie-breaker.
21562  *
21563  * **Note:** If the predicate is missing or empty then it defaults to `'+'`.
21564  *
21565  * @param {boolean=} reverse - If `true`, reverse the sorting order.
21566  * @param {(Function)=} comparator - The comparator function used to determine the relative order of
21567  *    value pairs. If omitted, the built-in comparator will be used.
21568  *
21569  * @returns {Array} - The sorted array.
21570  *
21571  *
21572  * @example
21573  * ### Ordering a table with `ngRepeat`
21574  *
21575  * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by
21576  * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means
21577  * it defaults to the built-in comparator.
21578  *
21579    <example name="orderBy-static" module="orderByExample1">
21580      <file name="index.html">
21581        <div ng-controller="ExampleController">
21582          <table class="friends">
21583            <tr>
21584              <th>Name</th>
21585              <th>Phone Number</th>
21586              <th>Age</th>
21587            </tr>
21588            <tr ng-repeat="friend in friends | orderBy:'-age'">
21589              <td>{{friend.name}}</td>
21590              <td>{{friend.phone}}</td>
21591              <td>{{friend.age}}</td>
21592            </tr>
21593          </table>
21594        </div>
21595      </file>
21596      <file name="script.js">
21597        angular.module('orderByExample1', [])
21598          .controller('ExampleController', ['$scope', function($scope) {
21599            $scope.friends = [
21600              {name: 'John',   phone: '555-1212',  age: 10},
21601              {name: 'Mary',   phone: '555-9876',  age: 19},
21602              {name: 'Mike',   phone: '555-4321',  age: 21},
21603              {name: 'Adam',   phone: '555-5678',  age: 35},
21604              {name: 'Julie',  phone: '555-8765',  age: 29}
21605            ];
21606          }]);
21607      </file>
21608      <file name="style.css">
21609        .friends {
21610          border-collapse: collapse;
21611        }
21612
21613        .friends th {
21614          border-bottom: 1px solid;
21615        }
21616        .friends td, .friends th {
21617          border-left: 1px solid;
21618          padding: 5px 10px;
21619        }
21620        .friends td:first-child, .friends th:first-child {
21621          border-left: none;
21622        }
21623      </file>
21624      <file name="protractor.js" type="protractor">
21625        // Element locators
21626        var names = element.all(by.repeater('friends').column('friend.name'));
21627
21628        it('should sort friends by age in reverse order', function() {
21629          expect(names.get(0).getText()).toBe('Adam');
21630          expect(names.get(1).getText()).toBe('Julie');
21631          expect(names.get(2).getText()).toBe('Mike');
21632          expect(names.get(3).getText()).toBe('Mary');
21633          expect(names.get(4).getText()).toBe('John');
21634        });
21635      </file>
21636    </example>
21637  * <hr />
21638  *
21639  * @example
21640  * ### Changing parameters dynamically
21641  *
21642  * All parameters can be changed dynamically. The next example shows how you can make the columns of
21643  * a table sortable, by binding the `expression` and `reverse` parameters to scope properties.
21644  *
21645    <example name="orderBy-dynamic" module="orderByExample2">
21646      <file name="index.html">
21647        <div ng-controller="ExampleController">
21648          <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
21649          <hr/>
21650          <button ng-click="propertyName = null; reverse = false">Set to unsorted</button>
21651          <hr/>
21652          <table class="friends">
21653            <tr>
21654              <th>
21655                <button ng-click="sortBy('name')">Name</button>
21656                <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
21657              </th>
21658              <th>
21659                <button ng-click="sortBy('phone')">Phone Number</button>
21660                <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
21661              </th>
21662              <th>
21663                <button ng-click="sortBy('age')">Age</button>
21664                <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
21665              </th>
21666            </tr>
21667            <tr ng-repeat="friend in friends | orderBy:propertyName:reverse">
21668              <td>{{friend.name}}</td>
21669              <td>{{friend.phone}}</td>
21670              <td>{{friend.age}}</td>
21671            </tr>
21672          </table>
21673        </div>
21674      </file>
21675      <file name="script.js">
21676        angular.module('orderByExample2', [])
21677          .controller('ExampleController', ['$scope', function($scope) {
21678            var friends = [
21679              {name: 'John',   phone: '555-1212',  age: 10},
21680              {name: 'Mary',   phone: '555-9876',  age: 19},
21681              {name: 'Mike',   phone: '555-4321',  age: 21},
21682              {name: 'Adam',   phone: '555-5678',  age: 35},
21683              {name: 'Julie',  phone: '555-8765',  age: 29}
21684            ];
21685
21686            $scope.propertyName = 'age';
21687            $scope.reverse = true;
21688            $scope.friends = friends;
21689
21690            $scope.sortBy = function(propertyName) {
21691              $scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;
21692              $scope.propertyName = propertyName;
21693            };
21694          }]);
21695      </file>
21696      <file name="style.css">
21697        .friends {
21698          border-collapse: collapse;
21699        }
21700
21701        .friends th {
21702          border-bottom: 1px solid;
21703        }
21704        .friends td, .friends th {
21705          border-left: 1px solid;
21706          padding: 5px 10px;
21707        }
21708        .friends td:first-child, .friends th:first-child {
21709          border-left: none;
21710        }
21711
21712        .sortorder:after {
21713          content: '\25b2';   // BLACK UP-POINTING TRIANGLE
21714        }
21715        .sortorder.reverse:after {
21716          content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
21717        }
21718      </file>
21719      <file name="protractor.js" type="protractor">
21720        // Element locators
21721        var unsortButton = element(by.partialButtonText('unsorted'));
21722        var nameHeader = element(by.partialButtonText('Name'));
21723        var phoneHeader = element(by.partialButtonText('Phone'));
21724        var ageHeader = element(by.partialButtonText('Age'));
21725        var firstName = element(by.repeater('friends').column('friend.name').row(0));
21726        var lastName = element(by.repeater('friends').column('friend.name').row(4));
21727
21728        it('should sort friends by some property, when clicking on the column header', function() {
21729          expect(firstName.getText()).toBe('Adam');
21730          expect(lastName.getText()).toBe('John');
21731
21732          phoneHeader.click();
21733          expect(firstName.getText()).toBe('John');
21734          expect(lastName.getText()).toBe('Mary');
21735
21736          nameHeader.click();
21737          expect(firstName.getText()).toBe('Adam');
21738          expect(lastName.getText()).toBe('Mike');
21739
21740          ageHeader.click();
21741          expect(firstName.getText()).toBe('John');
21742          expect(lastName.getText()).toBe('Adam');
21743        });
21744
21745        it('should sort friends in reverse order, when clicking on the same column', function() {
21746          expect(firstName.getText()).toBe('Adam');
21747          expect(lastName.getText()).toBe('John');
21748
21749          ageHeader.click();
21750          expect(firstName.getText()).toBe('John');
21751          expect(lastName.getText()).toBe('Adam');
21752
21753          ageHeader.click();
21754          expect(firstName.getText()).toBe('Adam');
21755          expect(lastName.getText()).toBe('John');
21756        });
21757
21758        it('should restore the original order, when clicking "Set to unsorted"', function() {
21759          expect(firstName.getText()).toBe('Adam');
21760          expect(lastName.getText()).toBe('John');
21761
21762          unsortButton.click();
21763          expect(firstName.getText()).toBe('John');
21764          expect(lastName.getText()).toBe('Julie');
21765        });
21766      </file>
21767    </example>
21768  * <hr />
21769  *
21770  * @example
21771  * ### Using `orderBy` inside a controller
21772  *
21773  * It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and
21774  * calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory
21775  * and retrieve the `orderBy` filter with `$filter('orderBy')`.)
21776  *
21777    <example name="orderBy-call-manually" module="orderByExample3">
21778      <file name="index.html">
21779        <div ng-controller="ExampleController">
21780          <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
21781          <hr/>
21782          <button ng-click="sortBy(null)">Set to unsorted</button>
21783          <hr/>
21784          <table class="friends">
21785            <tr>
21786              <th>
21787                <button ng-click="sortBy('name')">Name</button>
21788                <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
21789              </th>
21790              <th>
21791                <button ng-click="sortBy('phone')">Phone Number</button>
21792                <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
21793              </th>
21794              <th>
21795                <button ng-click="sortBy('age')">Age</button>
21796                <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
21797              </th>
21798            </tr>
21799            <tr ng-repeat="friend in friends">
21800              <td>{{friend.name}}</td>
21801              <td>{{friend.phone}}</td>
21802              <td>{{friend.age}}</td>
21803            </tr>
21804          </table>
21805        </div>
21806      </file>
21807      <file name="script.js">
21808        angular.module('orderByExample3', [])
21809          .controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) {
21810            var friends = [
21811              {name: 'John',   phone: '555-1212',  age: 10},
21812              {name: 'Mary',   phone: '555-9876',  age: 19},
21813              {name: 'Mike',   phone: '555-4321',  age: 21},
21814              {name: 'Adam',   phone: '555-5678',  age: 35},
21815              {name: 'Julie',  phone: '555-8765',  age: 29}
21816            ];
21817
21818            $scope.propertyName = 'age';
21819            $scope.reverse = true;
21820            $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
21821
21822            $scope.sortBy = function(propertyName) {
21823              $scope.reverse = (propertyName !== null && $scope.propertyName === propertyName)
21824                  ? !$scope.reverse : false;
21825              $scope.propertyName = propertyName;
21826              $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
21827            };
21828          }]);
21829      </file>
21830      <file name="style.css">
21831        .friends {
21832          border-collapse: collapse;
21833        }
21834
21835        .friends th {
21836          border-bottom: 1px solid;
21837        }
21838        .friends td, .friends th {
21839          border-left: 1px solid;
21840          padding: 5px 10px;
21841        }
21842        .friends td:first-child, .friends th:first-child {
21843          border-left: none;
21844        }
21845
21846        .sortorder:after {
21847          content: '\25b2';   // BLACK UP-POINTING TRIANGLE
21848        }
21849        .sortorder.reverse:after {
21850          content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
21851        }
21852      </file>
21853      <file name="protractor.js" type="protractor">
21854        // Element locators
21855        var unsortButton = element(by.partialButtonText('unsorted'));
21856        var nameHeader = element(by.partialButtonText('Name'));
21857        var phoneHeader = element(by.partialButtonText('Phone'));
21858        var ageHeader = element(by.partialButtonText('Age'));
21859        var firstName = element(by.repeater('friends').column('friend.name').row(0));
21860        var lastName = element(by.repeater('friends').column('friend.name').row(4));
21861
21862        it('should sort friends by some property, when clicking on the column header', function() {
21863          expect(firstName.getText()).toBe('Adam');
21864          expect(lastName.getText()).toBe('John');
21865
21866          phoneHeader.click();
21867          expect(firstName.getText()).toBe('John');
21868          expect(lastName.getText()).toBe('Mary');
21869
21870          nameHeader.click();
21871          expect(firstName.getText()).toBe('Adam');
21872          expect(lastName.getText()).toBe('Mike');
21873
21874          ageHeader.click();
21875          expect(firstName.getText()).toBe('John');
21876          expect(lastName.getText()).toBe('Adam');
21877        });
21878
21879        it('should sort friends in reverse order, when clicking on the same column', function() {
21880          expect(firstName.getText()).toBe('Adam');
21881          expect(lastName.getText()).toBe('John');
21882
21883          ageHeader.click();
21884          expect(firstName.getText()).toBe('John');
21885          expect(lastName.getText()).toBe('Adam');
21886
21887          ageHeader.click();
21888          expect(firstName.getText()).toBe('Adam');
21889          expect(lastName.getText()).toBe('John');
21890        });
21891
21892        it('should restore the original order, when clicking "Set to unsorted"', function() {
21893          expect(firstName.getText()).toBe('Adam');
21894          expect(lastName.getText()).toBe('John');
21895
21896          unsortButton.click();
21897          expect(firstName.getText()).toBe('John');
21898          expect(lastName.getText()).toBe('Julie');
21899        });
21900      </file>
21901    </example>
21902  * <hr />
21903  *
21904  * @example
21905  * ### Using a custom comparator
21906  *
21907  * If you have very specific requirements about the way items are sorted, you can pass your own
21908  * comparator function. For example, you might need to compare some strings in a locale-sensitive
21909  * way. (When specifying a custom comparator, you also need to pass a value for the `reverse`
21910  * argument - passing `false` retains the default sorting order, i.e. ascending.)
21911  *
21912    <example name="orderBy-custom-comparator" module="orderByExample4">
21913      <file name="index.html">
21914        <div ng-controller="ExampleController">
21915          <div class="friends-container custom-comparator">
21916            <h3>Locale-sensitive Comparator</h3>
21917            <table class="friends">
21918              <tr>
21919                <th>Name</th>
21920                <th>Favorite Letter</th>
21921              </tr>
21922              <tr ng-repeat="friend in friends | orderBy:'favoriteLetter':false:localeSensitiveComparator">
21923                <td>{{friend.name}}</td>
21924                <td>{{friend.favoriteLetter}}</td>
21925              </tr>
21926            </table>
21927          </div>
21928          <div class="friends-container default-comparator">
21929            <h3>Default Comparator</h3>
21930            <table class="friends">
21931              <tr>
21932                <th>Name</th>
21933                <th>Favorite Letter</th>
21934              </tr>
21935              <tr ng-repeat="friend in friends | orderBy:'favoriteLetter'">
21936                <td>{{friend.name}}</td>
21937                <td>{{friend.favoriteLetter}}</td>
21938              </tr>
21939            </table>
21940          </div>
21941        </div>
21942      </file>
21943      <file name="script.js">
21944        angular.module('orderByExample4', [])
21945          .controller('ExampleController', ['$scope', function($scope) {
21946            $scope.friends = [
21947              {name: 'John',   favoriteLetter: 'Ä'},
21948              {name: 'Mary',   favoriteLetter: 'Ãœ'},
21949              {name: 'Mike',   favoriteLetter: 'Ö'},
21950              {name: 'Adam',   favoriteLetter: 'H'},
21951              {name: 'Julie',  favoriteLetter: 'Z'}
21952            ];
21953
21954            $scope.localeSensitiveComparator = function(v1, v2) {
21955              // If we don't get strings, just compare by index
21956              if (v1.type !== 'string' || v2.type !== 'string') {
21957                return (v1.index < v2.index) ? -1 : 1;
21958              }
21959
21960              // Compare strings alphabetically, taking locale into account
21961              return v1.value.localeCompare(v2.value);
21962            };
21963          }]);
21964      </file>
21965      <file name="style.css">
21966        .friends-container {
21967          display: inline-block;
21968          margin: 0 30px;
21969        }
21970
21971        .friends {
21972          border-collapse: collapse;
21973        }
21974
21975        .friends th {
21976          border-bottom: 1px solid;
21977        }
21978        .friends td, .friends th {
21979          border-left: 1px solid;
21980          padding: 5px 10px;
21981        }
21982        .friends td:first-child, .friends th:first-child {
21983          border-left: none;
21984        }
21985      </file>
21986      <file name="protractor.js" type="protractor">
21987        // Element locators
21988        var container = element(by.css('.custom-comparator'));
21989        var names = container.all(by.repeater('friends').column('friend.name'));
21990
21991        it('should sort friends by favorite letter (in correct alphabetical order)', function() {
21992          expect(names.get(0).getText()).toBe('John');
21993          expect(names.get(1).getText()).toBe('Adam');
21994          expect(names.get(2).getText()).toBe('Mike');
21995          expect(names.get(3).getText()).toBe('Mary');
21996          expect(names.get(4).getText()).toBe('Julie');
21997        });
21998      </file>
21999    </example>
22000  *
22001  */
22002 orderByFilter.$inject = ['$parse'];
22003 function orderByFilter($parse) {
22004   return function(array, sortPredicate, reverseOrder, compareFn) {
22005
22006     if (array == null) return array;
22007     if (!isArrayLike(array)) {
22008       throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
22009     }
22010
22011     if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
22012     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
22013
22014     var predicates = processPredicates(sortPredicate);
22015
22016     var descending = reverseOrder ? -1 : 1;
22017
22018     // Define the `compare()` function. Use a default comparator if none is specified.
22019     var compare = isFunction(compareFn) ? compareFn : defaultCompare;
22020
22021     // The next three lines are a version of a Swartzian Transform idiom from Perl
22022     // (sometimes called the Decorate-Sort-Undecorate idiom)
22023     // See https://en.wikipedia.org/wiki/Schwartzian_transform
22024     var compareValues = Array.prototype.map.call(array, getComparisonObject);
22025     compareValues.sort(doComparison);
22026     array = compareValues.map(function(item) { return item.value; });
22027
22028     return array;
22029
22030     function getComparisonObject(value, index) {
22031       // NOTE: We are adding an extra `tieBreaker` value based on the element's index.
22032       // This will be used to keep the sort stable when none of the input predicates can
22033       // distinguish between two elements.
22034       return {
22035         value: value,
22036         tieBreaker: {value: index, type: 'number', index: index},
22037         predicateValues: predicates.map(function(predicate) {
22038           return getPredicateValue(predicate.get(value), index);
22039         })
22040       };
22041     }
22042
22043     function doComparison(v1, v2) {
22044       for (var i = 0, ii = predicates.length; i < ii; i++) {
22045         var result = compare(v1.predicateValues[i], v2.predicateValues[i]);
22046         if (result) {
22047           return result * predicates[i].descending * descending;
22048         }
22049       }
22050
22051       return compare(v1.tieBreaker, v2.tieBreaker) * descending;
22052     }
22053   };
22054
22055   function processPredicates(sortPredicates) {
22056     return sortPredicates.map(function(predicate) {
22057       var descending = 1, get = identity;
22058
22059       if (isFunction(predicate)) {
22060         get = predicate;
22061       } else if (isString(predicate)) {
22062         if ((predicate.charAt(0) === '+' || predicate.charAt(0) === '-')) {
22063           descending = predicate.charAt(0) === '-' ? -1 : 1;
22064           predicate = predicate.substring(1);
22065         }
22066         if (predicate !== '') {
22067           get = $parse(predicate);
22068           if (get.constant) {
22069             var key = get();
22070             get = function(value) { return value[key]; };
22071           }
22072         }
22073       }
22074       return {get: get, descending: descending};
22075     });
22076   }
22077
22078   function isPrimitive(value) {
22079     switch (typeof value) {
22080       case 'number': /* falls through */
22081       case 'boolean': /* falls through */
22082       case 'string':
22083         return true;
22084       default:
22085         return false;
22086     }
22087   }
22088
22089   function objectValue(value) {
22090     // If `valueOf` is a valid function use that
22091     if (isFunction(value.valueOf)) {
22092       value = value.valueOf();
22093       if (isPrimitive(value)) return value;
22094     }
22095     // If `toString` is a valid function and not the one from `Object.prototype` use that
22096     if (hasCustomToString(value)) {
22097       value = value.toString();
22098       if (isPrimitive(value)) return value;
22099     }
22100
22101     return value;
22102   }
22103
22104   function getPredicateValue(value, index) {
22105     var type = typeof value;
22106     if (value === null) {
22107       type = 'string';
22108       value = 'null';
22109     } else if (type === 'object') {
22110       value = objectValue(value);
22111     }
22112     return {value: value, type: type, index: index};
22113   }
22114
22115   function defaultCompare(v1, v2) {
22116     var result = 0;
22117     var type1 = v1.type;
22118     var type2 = v2.type;
22119
22120     if (type1 === type2) {
22121       var value1 = v1.value;
22122       var value2 = v2.value;
22123
22124       if (type1 === 'string') {
22125         // Compare strings case-insensitively
22126         value1 = value1.toLowerCase();
22127         value2 = value2.toLowerCase();
22128       } else if (type1 === 'object') {
22129         // For basic objects, use the position of the object
22130         // in the collection instead of the value
22131         if (isObject(value1)) value1 = v1.index;
22132         if (isObject(value2)) value2 = v2.index;
22133       }
22134
22135       if (value1 !== value2) {
22136         result = value1 < value2 ? -1 : 1;
22137       }
22138     } else {
22139       result = type1 < type2 ? -1 : 1;
22140     }
22141
22142     return result;
22143   }
22144 }
22145
22146 function ngDirective(directive) {
22147   if (isFunction(directive)) {
22148     directive = {
22149       link: directive
22150     };
22151   }
22152   directive.restrict = directive.restrict || 'AC';
22153   return valueFn(directive);
22154 }
22155
22156 /**
22157  * @ngdoc directive
22158  * @name a
22159  * @restrict E
22160  *
22161  * @description
22162  * Modifies the default behavior of the html a tag so that the default action is prevented when
22163  * the href attribute is empty.
22164  *
22165  * For dynamically creating `href` attributes for a tags, see the {@link ng.ngHref `ngHref`} directive.
22166  */
22167 var htmlAnchorDirective = valueFn({
22168   restrict: 'E',
22169   compile: function(element, attr) {
22170     if (!attr.href && !attr.xlinkHref) {
22171       return function(scope, element) {
22172         // If the linked element is not an anchor tag anymore, do nothing
22173         if (element[0].nodeName.toLowerCase() !== 'a') return;
22174
22175         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
22176         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
22177                    'xlink:href' : 'href';
22178         element.on('click', function(event) {
22179           // if we have no href url, then don't navigate anywhere.
22180           if (!element.attr(href)) {
22181             event.preventDefault();
22182           }
22183         });
22184       };
22185     }
22186   }
22187 });
22188
22189 /**
22190  * @ngdoc directive
22191  * @name ngHref
22192  * @restrict A
22193  * @priority 99
22194  *
22195  * @description
22196  * Using Angular markup like `{{hash}}` in an href attribute will
22197  * make the link go to the wrong URL if the user clicks it before
22198  * Angular has a chance to replace the `{{hash}}` markup with its
22199  * value. Until Angular replaces the markup the link will be broken
22200  * and will most likely return a 404 error. The `ngHref` directive
22201  * solves this problem.
22202  *
22203  * The wrong way to write it:
22204  * ```html
22205  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
22206  * ```
22207  *
22208  * The correct way to write it:
22209  * ```html
22210  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
22211  * ```
22212  *
22213  * @element A
22214  * @param {template} ngHref any string which can contain `{{}}` markup.
22215  *
22216  * @example
22217  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
22218  * in links and their different behaviors:
22219     <example name="ng-href">
22220       <file name="index.html">
22221         <input ng-model="value" /><br />
22222         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
22223         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
22224         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
22225         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
22226         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
22227         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
22228       </file>
22229       <file name="protractor.js" type="protractor">
22230         it('should execute ng-click but not reload when href without value', function() {
22231           element(by.id('link-1')).click();
22232           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
22233           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
22234         });
22235
22236         it('should execute ng-click but not reload when href empty string', function() {
22237           element(by.id('link-2')).click();
22238           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
22239           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
22240         });
22241
22242         it('should execute ng-click and change url when ng-href specified', function() {
22243           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
22244
22245           element(by.id('link-3')).click();
22246
22247           // At this point, we navigate away from an Angular page, so we need
22248           // to use browser.driver to get the base webdriver.
22249
22250           browser.wait(function() {
22251             return browser.driver.getCurrentUrl().then(function(url) {
22252               return url.match(/\/123$/);
22253             });
22254           }, 5000, 'page should navigate to /123');
22255         });
22256
22257         it('should execute ng-click but not reload when href empty string and name specified', function() {
22258           element(by.id('link-4')).click();
22259           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
22260           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
22261         });
22262
22263         it('should execute ng-click but not reload when no href but name specified', function() {
22264           element(by.id('link-5')).click();
22265           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
22266           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
22267         });
22268
22269         it('should only change url when only ng-href', function() {
22270           element(by.model('value')).clear();
22271           element(by.model('value')).sendKeys('6');
22272           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
22273
22274           element(by.id('link-6')).click();
22275
22276           // At this point, we navigate away from an Angular page, so we need
22277           // to use browser.driver to get the base webdriver.
22278           browser.wait(function() {
22279             return browser.driver.getCurrentUrl().then(function(url) {
22280               return url.match(/\/6$/);
22281             });
22282           }, 5000, 'page should navigate to /6');
22283         });
22284       </file>
22285     </example>
22286  */
22287
22288 /**
22289  * @ngdoc directive
22290  * @name ngSrc
22291  * @restrict A
22292  * @priority 99
22293  *
22294  * @description
22295  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
22296  * work right: The browser will fetch from the URL with the literal
22297  * text `{{hash}}` until Angular replaces the expression inside
22298  * `{{hash}}`. The `ngSrc` directive solves this problem.
22299  *
22300  * The buggy way to write it:
22301  * ```html
22302  * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
22303  * ```
22304  *
22305  * The correct way to write it:
22306  * ```html
22307  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
22308  * ```
22309  *
22310  * @element IMG
22311  * @param {template} ngSrc any string which can contain `{{}}` markup.
22312  */
22313
22314 /**
22315  * @ngdoc directive
22316  * @name ngSrcset
22317  * @restrict A
22318  * @priority 99
22319  *
22320  * @description
22321  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
22322  * work right: The browser will fetch from the URL with the literal
22323  * text `{{hash}}` until Angular replaces the expression inside
22324  * `{{hash}}`. The `ngSrcset` directive solves this problem.
22325  *
22326  * The buggy way to write it:
22327  * ```html
22328  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
22329  * ```
22330  *
22331  * The correct way to write it:
22332  * ```html
22333  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
22334  * ```
22335  *
22336  * @element IMG
22337  * @param {template} ngSrcset any string which can contain `{{}}` markup.
22338  */
22339
22340 /**
22341  * @ngdoc directive
22342  * @name ngDisabled
22343  * @restrict A
22344  * @priority 100
22345  *
22346  * @description
22347  *
22348  * This directive sets the `disabled` attribute on the element if the
22349  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
22350  *
22351  * A special directive is necessary because we cannot use interpolation inside the `disabled`
22352  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
22353  *
22354  * @example
22355     <example name="ng-disabled">
22356       <file name="index.html">
22357         <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
22358         <button ng-model="button" ng-disabled="checked">Button</button>
22359       </file>
22360       <file name="protractor.js" type="protractor">
22361         it('should toggle button', function() {
22362           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
22363           element(by.model('checked')).click();
22364           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
22365         });
22366       </file>
22367     </example>
22368  *
22369  * @element INPUT
22370  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
22371  *     then the `disabled` attribute will be set on the element
22372  */
22373
22374
22375 /**
22376  * @ngdoc directive
22377  * @name ngChecked
22378  * @restrict A
22379  * @priority 100
22380  *
22381  * @description
22382  * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
22383  *
22384  * Note that this directive should not be used together with {@link ngModel `ngModel`},
22385  * as this can lead to unexpected behavior.
22386  *
22387  * A special directive is necessary because we cannot use interpolation inside the `checked`
22388  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
22389  *
22390  * @example
22391     <example name="ng-checked">
22392       <file name="index.html">
22393         <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
22394         <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
22395       </file>
22396       <file name="protractor.js" type="protractor">
22397         it('should check both checkBoxes', function() {
22398           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
22399           element(by.model('master')).click();
22400           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
22401         });
22402       </file>
22403     </example>
22404  *
22405  * @element INPUT
22406  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
22407  *     then the `checked` attribute will be set on the element
22408  */
22409
22410
22411 /**
22412  * @ngdoc directive
22413  * @name ngReadonly
22414  * @restrict A
22415  * @priority 100
22416  *
22417  * @description
22418  *
22419  * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.
22420  * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on
22421  * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.
22422  *
22423  * A special directive is necessary because we cannot use interpolation inside the `readonly`
22424  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
22425  *
22426  * @example
22427     <example name="ng-readonly">
22428       <file name="index.html">
22429         <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
22430         <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
22431       </file>
22432       <file name="protractor.js" type="protractor">
22433         it('should toggle readonly attr', function() {
22434           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
22435           element(by.model('checked')).click();
22436           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
22437         });
22438       </file>
22439     </example>
22440  *
22441  * @element INPUT
22442  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
22443  *     then special attribute "readonly" will be set on the element
22444  */
22445
22446
22447 /**
22448  * @ngdoc directive
22449  * @name ngSelected
22450  * @restrict A
22451  * @priority 100
22452  *
22453  * @description
22454  *
22455  * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
22456  *
22457  * A special directive is necessary because we cannot use interpolation inside the `selected`
22458  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
22459  *
22460  * <div class="alert alert-warning">
22461  *   **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only
22462  *   sets the `selected` attribute on the element. If you are using `ngModel` on the select, you
22463  *   should not use `ngSelected` on the options, as `ngModel` will set the select value and
22464  *   selected options.
22465  * </div>
22466  *
22467  * @example
22468     <example name="ng-selected">
22469       <file name="index.html">
22470         <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
22471         <select aria-label="ngSelected demo">
22472           <option>Hello!</option>
22473           <option id="greet" ng-selected="selected">Greetings!</option>
22474         </select>
22475       </file>
22476       <file name="protractor.js" type="protractor">
22477         it('should select Greetings!', function() {
22478           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
22479           element(by.model('selected')).click();
22480           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
22481         });
22482       </file>
22483     </example>
22484  *
22485  * @element OPTION
22486  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
22487  *     then special attribute "selected" will be set on the element
22488  */
22489
22490 /**
22491  * @ngdoc directive
22492  * @name ngOpen
22493  * @restrict A
22494  * @priority 100
22495  *
22496  * @description
22497  *
22498  * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
22499  *
22500  * A special directive is necessary because we cannot use interpolation inside the `open`
22501  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
22502  *
22503  * ## A note about browser compatibility
22504  *
22505  * Edge, Firefox, and Internet Explorer do not support the `details` element, it is
22506  * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.
22507  *
22508  * @example
22509      <example name="ng-open">
22510        <file name="index.html">
22511          <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
22512          <details id="details" ng-open="open">
22513             <summary>Show/Hide me</summary>
22514          </details>
22515        </file>
22516        <file name="protractor.js" type="protractor">
22517          it('should toggle open', function() {
22518            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
22519            element(by.model('open')).click();
22520            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
22521          });
22522        </file>
22523      </example>
22524  *
22525  * @element DETAILS
22526  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
22527  *     then special attribute "open" will be set on the element
22528  */
22529
22530 var ngAttributeAliasDirectives = {};
22531
22532 // boolean attrs are evaluated
22533 forEach(BOOLEAN_ATTR, function(propName, attrName) {
22534   // binding to multiple is not supported
22535   if (propName === 'multiple') return;
22536
22537   function defaultLinkFn(scope, element, attr) {
22538     scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
22539       attr.$set(attrName, !!value);
22540     });
22541   }
22542
22543   var normalized = directiveNormalize('ng-' + attrName);
22544   var linkFn = defaultLinkFn;
22545
22546   if (propName === 'checked') {
22547     linkFn = function(scope, element, attr) {
22548       // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
22549       if (attr.ngModel !== attr[normalized]) {
22550         defaultLinkFn(scope, element, attr);
22551       }
22552     };
22553   }
22554
22555   ngAttributeAliasDirectives[normalized] = function() {
22556     return {
22557       restrict: 'A',
22558       priority: 100,
22559       link: linkFn
22560     };
22561   };
22562 });
22563
22564 // aliased input attrs are evaluated
22565 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
22566   ngAttributeAliasDirectives[ngAttr] = function() {
22567     return {
22568       priority: 100,
22569       link: function(scope, element, attr) {
22570         //special case ngPattern when a literal regular expression value
22571         //is used as the expression (this way we don't have to watch anything).
22572         if (ngAttr === 'ngPattern' && attr.ngPattern.charAt(0) === '/') {
22573           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
22574           if (match) {
22575             attr.$set('ngPattern', new RegExp(match[1], match[2]));
22576             return;
22577           }
22578         }
22579
22580         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
22581           attr.$set(ngAttr, value);
22582         });
22583       }
22584     };
22585   };
22586 });
22587
22588 // ng-src, ng-srcset, ng-href are interpolated
22589 forEach(['src', 'srcset', 'href'], function(attrName) {
22590   var normalized = directiveNormalize('ng-' + attrName);
22591   ngAttributeAliasDirectives[normalized] = function() {
22592     return {
22593       priority: 99, // it needs to run after the attributes are interpolated
22594       link: function(scope, element, attr) {
22595         var propName = attrName,
22596             name = attrName;
22597
22598         if (attrName === 'href' &&
22599             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
22600           name = 'xlinkHref';
22601           attr.$attr[name] = 'xlink:href';
22602           propName = null;
22603         }
22604
22605         attr.$observe(normalized, function(value) {
22606           if (!value) {
22607             if (attrName === 'href') {
22608               attr.$set(name, null);
22609             }
22610             return;
22611           }
22612
22613           attr.$set(name, value);
22614
22615           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
22616           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
22617           // to set the property as well to achieve the desired effect.
22618           // we use attr[attrName] value since $set can sanitize the url.
22619           if (msie && propName) element.prop(propName, attr[name]);
22620         });
22621       }
22622     };
22623   };
22624 });
22625
22626 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
22627  */
22628 var nullFormCtrl = {
22629   $addControl: noop,
22630   $$renameControl: nullFormRenameControl,
22631   $removeControl: noop,
22632   $setValidity: noop,
22633   $setDirty: noop,
22634   $setPristine: noop,
22635   $setSubmitted: noop
22636 },
22637 SUBMITTED_CLASS = 'ng-submitted';
22638
22639 function nullFormRenameControl(control, name) {
22640   control.$name = name;
22641 }
22642
22643 /**
22644  * @ngdoc type
22645  * @name form.FormController
22646  *
22647  * @property {boolean} $pristine True if user has not interacted with the form yet.
22648  * @property {boolean} $dirty True if user has already interacted with the form.
22649  * @property {boolean} $valid True if all of the containing forms and controls are valid.
22650  * @property {boolean} $invalid True if at least one containing control or form is invalid.
22651  * @property {boolean} $pending True if at least one containing control or form is pending.
22652  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
22653  *
22654  * @property {Object} $error Is an object hash, containing references to controls or
22655  *  forms with failing validators, where:
22656  *
22657  *  - keys are validation tokens (error names),
22658  *  - values are arrays of controls or forms that have a failing validator for given error name.
22659  *
22660  *  Built-in validation tokens:
22661  *
22662  *  - `email`
22663  *  - `max`
22664  *  - `maxlength`
22665  *  - `min`
22666  *  - `minlength`
22667  *  - `number`
22668  *  - `pattern`
22669  *  - `required`
22670  *  - `url`
22671  *  - `date`
22672  *  - `datetimelocal`
22673  *  - `time`
22674  *  - `week`
22675  *  - `month`
22676  *
22677  * @description
22678  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
22679  * such as being valid/invalid or dirty/pristine.
22680  *
22681  * Each {@link ng.directive:form form} directive creates an instance
22682  * of `FormController`.
22683  *
22684  */
22685 //asks for $scope to fool the BC controller module
22686 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
22687 function FormController(element, attrs, $scope, $animate, $interpolate) {
22688   var form = this,
22689       controls = [];
22690
22691   // init state
22692   form.$error = {};
22693   form.$$success = {};
22694   form.$pending = undefined;
22695   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
22696   form.$dirty = false;
22697   form.$pristine = true;
22698   form.$valid = true;
22699   form.$invalid = false;
22700   form.$submitted = false;
22701   form.$$parentForm = nullFormCtrl;
22702
22703   /**
22704    * @ngdoc method
22705    * @name form.FormController#$rollbackViewValue
22706    *
22707    * @description
22708    * Rollback all form controls pending updates to the `$modelValue`.
22709    *
22710    * Updates may be pending by a debounced event or because the input is waiting for a some future
22711    * event defined in `ng-model-options`. This method is typically needed by the reset button of
22712    * a form that uses `ng-model-options` to pend updates.
22713    */
22714   form.$rollbackViewValue = function() {
22715     forEach(controls, function(control) {
22716       control.$rollbackViewValue();
22717     });
22718   };
22719
22720   /**
22721    * @ngdoc method
22722    * @name form.FormController#$commitViewValue
22723    *
22724    * @description
22725    * Commit all form controls pending updates to the `$modelValue`.
22726    *
22727    * Updates may be pending by a debounced event or because the input is waiting for a some future
22728    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
22729    * usually handles calling this in response to input events.
22730    */
22731   form.$commitViewValue = function() {
22732     forEach(controls, function(control) {
22733       control.$commitViewValue();
22734     });
22735   };
22736
22737   /**
22738    * @ngdoc method
22739    * @name form.FormController#$addControl
22740    * @param {object} control control object, either a {@link form.FormController} or an
22741    * {@link ngModel.NgModelController}
22742    *
22743    * @description
22744    * Register a control with the form. Input elements using ngModelController do this automatically
22745    * when they are linked.
22746    *
22747    * Note that the current state of the control will not be reflected on the new parent form. This
22748    * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
22749    * state.
22750    *
22751    * However, if the method is used programmatically, for example by adding dynamically created controls,
22752    * or controls that have been previously removed without destroying their corresponding DOM element,
22753    * it's the developers responsibility to make sure the current state propagates to the parent form.
22754    *
22755    * For example, if an input control is added that is already `$dirty` and has `$error` properties,
22756    * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
22757    */
22758   form.$addControl = function(control) {
22759     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
22760     // and not added to the scope.  Now we throw an error.
22761     assertNotHasOwnProperty(control.$name, 'input');
22762     controls.push(control);
22763
22764     if (control.$name) {
22765       form[control.$name] = control;
22766     }
22767
22768     control.$$parentForm = form;
22769   };
22770
22771   // Private API: rename a form control
22772   form.$$renameControl = function(control, newName) {
22773     var oldName = control.$name;
22774
22775     if (form[oldName] === control) {
22776       delete form[oldName];
22777     }
22778     form[newName] = control;
22779     control.$name = newName;
22780   };
22781
22782   /**
22783    * @ngdoc method
22784    * @name form.FormController#$removeControl
22785    * @param {object} control control object, either a {@link form.FormController} or an
22786    * {@link ngModel.NgModelController}
22787    *
22788    * @description
22789    * Deregister a control from the form.
22790    *
22791    * Input elements using ngModelController do this automatically when they are destroyed.
22792    *
22793    * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
22794    * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
22795    * different from case to case. For example, removing the only `$dirty` control from a form may or
22796    * may not mean that the form is still `$dirty`.
22797    */
22798   form.$removeControl = function(control) {
22799     if (control.$name && form[control.$name] === control) {
22800       delete form[control.$name];
22801     }
22802     forEach(form.$pending, function(value, name) {
22803       form.$setValidity(name, null, control);
22804     });
22805     forEach(form.$error, function(value, name) {
22806       form.$setValidity(name, null, control);
22807     });
22808     forEach(form.$$success, function(value, name) {
22809       form.$setValidity(name, null, control);
22810     });
22811
22812     arrayRemove(controls, control);
22813     control.$$parentForm = nullFormCtrl;
22814   };
22815
22816
22817   /**
22818    * @ngdoc method
22819    * @name form.FormController#$setValidity
22820    *
22821    * @description
22822    * Sets the validity of a form control.
22823    *
22824    * This method will also propagate to parent forms.
22825    */
22826   addSetValidityMethod({
22827     ctrl: this,
22828     $element: element,
22829     set: function(object, property, controller) {
22830       var list = object[property];
22831       if (!list) {
22832         object[property] = [controller];
22833       } else {
22834         var index = list.indexOf(controller);
22835         if (index === -1) {
22836           list.push(controller);
22837         }
22838       }
22839     },
22840     unset: function(object, property, controller) {
22841       var list = object[property];
22842       if (!list) {
22843         return;
22844       }
22845       arrayRemove(list, controller);
22846       if (list.length === 0) {
22847         delete object[property];
22848       }
22849     },
22850     $animate: $animate
22851   });
22852
22853   /**
22854    * @ngdoc method
22855    * @name form.FormController#$setDirty
22856    *
22857    * @description
22858    * Sets the form to a dirty state.
22859    *
22860    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
22861    * state (ng-dirty class). This method will also propagate to parent forms.
22862    */
22863   form.$setDirty = function() {
22864     $animate.removeClass(element, PRISTINE_CLASS);
22865     $animate.addClass(element, DIRTY_CLASS);
22866     form.$dirty = true;
22867     form.$pristine = false;
22868     form.$$parentForm.$setDirty();
22869   };
22870
22871   /**
22872    * @ngdoc method
22873    * @name form.FormController#$setPristine
22874    *
22875    * @description
22876    * Sets the form to its pristine state.
22877    *
22878    * This method sets the form's `$pristine` state to true, the `$dirty` state to false, removes
22879    * the `ng-dirty` class and adds the `ng-pristine` class. Additionally, it sets the `$submitted`
22880    * state to false.
22881    *
22882    * This method will also propagate to all the controls contained in this form.
22883    *
22884    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
22885    * saving or resetting it.
22886    */
22887   form.$setPristine = function() {
22888     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
22889     form.$dirty = false;
22890     form.$pristine = true;
22891     form.$submitted = false;
22892     forEach(controls, function(control) {
22893       control.$setPristine();
22894     });
22895   };
22896
22897   /**
22898    * @ngdoc method
22899    * @name form.FormController#$setUntouched
22900    *
22901    * @description
22902    * Sets the form to its untouched state.
22903    *
22904    * This method can be called to remove the 'ng-touched' class and set the form controls to their
22905    * untouched state (ng-untouched class).
22906    *
22907    * Setting a form controls back to their untouched state is often useful when setting the form
22908    * back to its pristine state.
22909    */
22910   form.$setUntouched = function() {
22911     forEach(controls, function(control) {
22912       control.$setUntouched();
22913     });
22914   };
22915
22916   /**
22917    * @ngdoc method
22918    * @name form.FormController#$setSubmitted
22919    *
22920    * @description
22921    * Sets the form to its submitted state.
22922    */
22923   form.$setSubmitted = function() {
22924     $animate.addClass(element, SUBMITTED_CLASS);
22925     form.$submitted = true;
22926     form.$$parentForm.$setSubmitted();
22927   };
22928 }
22929
22930 /**
22931  * @ngdoc directive
22932  * @name ngForm
22933  * @restrict EAC
22934  *
22935  * @description
22936  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
22937  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
22938  * sub-group of controls needs to be determined.
22939  *
22940  * Note: the purpose of `ngForm` is to group controls,
22941  * but not to be a replacement for the `<form>` tag with all of its capabilities
22942  * (e.g. posting to the server, ...).
22943  *
22944  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
22945  *                       related scope, under this name.
22946  *
22947  */
22948
22949  /**
22950  * @ngdoc directive
22951  * @name form
22952  * @restrict E
22953  *
22954  * @description
22955  * Directive that instantiates
22956  * {@link form.FormController FormController}.
22957  *
22958  * If the `name` attribute is specified, the form controller is published onto the current scope under
22959  * this name.
22960  *
22961  * # Alias: {@link ng.directive:ngForm `ngForm`}
22962  *
22963  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
22964  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
22965  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
22966  * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
22967  * of controls needs to be determined.
22968  *
22969  * # CSS classes
22970  *  - `ng-valid` is set if the form is valid.
22971  *  - `ng-invalid` is set if the form is invalid.
22972  *  - `ng-pending` is set if the form is pending.
22973  *  - `ng-pristine` is set if the form is pristine.
22974  *  - `ng-dirty` is set if the form is dirty.
22975  *  - `ng-submitted` is set if the form was submitted.
22976  *
22977  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
22978  *
22979  *
22980  * # Submitting a form and preventing the default action
22981  *
22982  * Since the role of forms in client-side Angular applications is different than in classical
22983  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
22984  * page reload that sends the data to the server. Instead some javascript logic should be triggered
22985  * to handle the form submission in an application-specific way.
22986  *
22987  * For this reason, Angular prevents the default action (form submission to the server) unless the
22988  * `<form>` element has an `action` attribute specified.
22989  *
22990  * You can use one of the following two ways to specify what javascript method should be called when
22991  * a form is submitted:
22992  *
22993  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
22994  * - {@link ng.directive:ngClick ngClick} directive on the first
22995   *  button or input field of type submit (input[type=submit])
22996  *
22997  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
22998  * or {@link ng.directive:ngClick ngClick} directives.
22999  * This is because of the following form submission rules in the HTML specification:
23000  *
23001  * - If a form has only one input field then hitting enter in this field triggers form submit
23002  * (`ngSubmit`)
23003  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
23004  * doesn't trigger submit
23005  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
23006  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
23007  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
23008  *
23009  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
23010  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
23011  * to have access to the updated model.
23012  *
23013  * ## Animation Hooks
23014  *
23015  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
23016  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
23017  * other validations that are performed within the form. Animations in ngForm are similar to how
23018  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
23019  * as JS animations.
23020  *
23021  * The following example shows a simple way to utilize CSS transitions to style a form element
23022  * that has been rendered as invalid after it has been validated:
23023  *
23024  * <pre>
23025  * //be sure to include ngAnimate as a module to hook into more
23026  * //advanced animations
23027  * .my-form {
23028  *   transition:0.5s linear all;
23029  *   background: white;
23030  * }
23031  * .my-form.ng-invalid {
23032  *   background: red;
23033  *   color:white;
23034  * }
23035  * </pre>
23036  *
23037  * @example
23038     <example name="ng-form" deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
23039       <file name="index.html">
23040        <script>
23041          angular.module('formExample', [])
23042            .controller('FormController', ['$scope', function($scope) {
23043              $scope.userType = 'guest';
23044            }]);
23045        </script>
23046        <style>
23047         .my-form {
23048           transition:all linear 0.5s;
23049           background: transparent;
23050         }
23051         .my-form.ng-invalid {
23052           background: red;
23053         }
23054        </style>
23055        <form name="myForm" ng-controller="FormController" class="my-form">
23056          userType: <input name="input" ng-model="userType" required>
23057          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
23058          <code>userType = {{userType}}</code><br>
23059          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
23060          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
23061          <code>myForm.$valid = {{myForm.$valid}}</code><br>
23062          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
23063         </form>
23064       </file>
23065       <file name="protractor.js" type="protractor">
23066         it('should initialize to model', function() {
23067           var userType = element(by.binding('userType'));
23068           var valid = element(by.binding('myForm.input.$valid'));
23069
23070           expect(userType.getText()).toContain('guest');
23071           expect(valid.getText()).toContain('true');
23072         });
23073
23074         it('should be invalid if empty', function() {
23075           var userType = element(by.binding('userType'));
23076           var valid = element(by.binding('myForm.input.$valid'));
23077           var userInput = element(by.model('userType'));
23078
23079           userInput.clear();
23080           userInput.sendKeys('');
23081
23082           expect(userType.getText()).toEqual('userType =');
23083           expect(valid.getText()).toContain('false');
23084         });
23085       </file>
23086     </example>
23087  *
23088  * @param {string=} name Name of the form. If specified, the form controller will be published into
23089  *                       related scope, under this name.
23090  */
23091 var formDirectiveFactory = function(isNgForm) {
23092   return ['$timeout', '$parse', function($timeout, $parse) {
23093     var formDirective = {
23094       name: 'form',
23095       restrict: isNgForm ? 'EAC' : 'E',
23096       require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
23097       controller: FormController,
23098       compile: function ngFormCompile(formElement, attr) {
23099         // Setup initial state of the control
23100         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
23101
23102         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
23103
23104         return {
23105           pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
23106             var controller = ctrls[0];
23107
23108             // if `action` attr is not present on the form, prevent the default action (submission)
23109             if (!('action' in attr)) {
23110               // we can't use jq events because if a form is destroyed during submission the default
23111               // action is not prevented. see #1238
23112               //
23113               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
23114               // page reload if the form was destroyed by submission of the form via a click handler
23115               // on a button in the form. Looks like an IE9 specific bug.
23116               var handleFormSubmission = function(event) {
23117                 scope.$apply(function() {
23118                   controller.$commitViewValue();
23119                   controller.$setSubmitted();
23120                 });
23121
23122                 event.preventDefault();
23123               };
23124
23125               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
23126
23127               // unregister the preventDefault listener so that we don't not leak memory but in a
23128               // way that will achieve the prevention of the default action.
23129               formElement.on('$destroy', function() {
23130                 $timeout(function() {
23131                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
23132                 }, 0, false);
23133               });
23134             }
23135
23136             var parentFormCtrl = ctrls[1] || controller.$$parentForm;
23137             parentFormCtrl.$addControl(controller);
23138
23139             var setter = nameAttr ? getSetter(controller.$name) : noop;
23140
23141             if (nameAttr) {
23142               setter(scope, controller);
23143               attr.$observe(nameAttr, function(newValue) {
23144                 if (controller.$name === newValue) return;
23145                 setter(scope, undefined);
23146                 controller.$$parentForm.$$renameControl(controller, newValue);
23147                 setter = getSetter(controller.$name);
23148                 setter(scope, controller);
23149               });
23150             }
23151             formElement.on('$destroy', function() {
23152               controller.$$parentForm.$removeControl(controller);
23153               setter(scope, undefined);
23154               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
23155             });
23156           }
23157         };
23158       }
23159     };
23160
23161     return formDirective;
23162
23163     function getSetter(expression) {
23164       if (expression === '') {
23165         //create an assignable expression, so forms with an empty name can be renamed later
23166         return $parse('this[""]').assign;
23167       }
23168       return $parse(expression).assign || noop;
23169     }
23170   }];
23171 };
23172
23173 var formDirective = formDirectiveFactory();
23174 var ngFormDirective = formDirectiveFactory(true);
23175
23176 /* global
23177   VALID_CLASS: false,
23178   INVALID_CLASS: false,
23179   PRISTINE_CLASS: false,
23180   DIRTY_CLASS: false,
23181   ngModelMinErr: false
23182 */
23183
23184 // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
23185 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)$/;
23186 // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
23187 // Note: We are being more lenient, because browsers are too.
23188 //   1. Scheme
23189 //   2. Slashes
23190 //   3. Username
23191 //   4. Password
23192 //   5. Hostname
23193 //   6. Port
23194 //   7. Path
23195 //   8. Query
23196 //   9. Fragment
23197 //                 1111111111111111 222   333333    44444        55555555555555555555555     666     77777777     8888888     999
23198 var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
23199 // eslint-disable-next-line max-len
23200 var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
23201 var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
23202 var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
23203 var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
23204 var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
23205 var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
23206 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
23207
23208 var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
23209 var PARTIAL_VALIDATION_TYPES = createMap();
23210 forEach('date,datetime-local,month,time,week'.split(','), function(type) {
23211   PARTIAL_VALIDATION_TYPES[type] = true;
23212 });
23213
23214 var inputType = {
23215
23216   /**
23217    * @ngdoc input
23218    * @name input[text]
23219    *
23220    * @description
23221    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
23222    *
23223    *
23224    * @param {string} ngModel Assignable angular expression to data-bind to.
23225    * @param {string=} name Property name of the form under which the control is published.
23226    * @param {string=} required Adds `required` validation error key if the value is not entered.
23227    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23228    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23229    *    `required` when you want to data-bind to the `required` attribute.
23230    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
23231    *    minlength.
23232    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
23233    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
23234    *    any length.
23235    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
23236    *    that contains the regular expression body that will be converted to a regular expression
23237    *    as in the ngPattern directive.
23238    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
23239    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
23240    *    If the expression evaluates to a RegExp object, then this is used directly.
23241    *    If the expression evaluates to a string, then it will be converted to a RegExp
23242    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
23243    *    `new RegExp('^abc$')`.<br />
23244    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
23245    *    start at the index of the last search's match, thus not taking the whole input value into
23246    *    account.
23247    * @param {string=} ngChange Angular expression to be executed when input changes due to user
23248    *    interaction with the input element.
23249    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
23250    *    This parameter is ignored for input[type=password] controls, which will never trim the
23251    *    input.
23252    *
23253    * @example
23254       <example name="text-input-directive" module="textInputExample">
23255         <file name="index.html">
23256          <script>
23257            angular.module('textInputExample', [])
23258              .controller('ExampleController', ['$scope', function($scope) {
23259                $scope.example = {
23260                  text: 'guest',
23261                  word: /^\s*\w*\s*$/
23262                };
23263              }]);
23264          </script>
23265          <form name="myForm" ng-controller="ExampleController">
23266            <label>Single word:
23267              <input type="text" name="input" ng-model="example.text"
23268                     ng-pattern="example.word" required ng-trim="false">
23269            </label>
23270            <div role="alert">
23271              <span class="error" ng-show="myForm.input.$error.required">
23272                Required!</span>
23273              <span class="error" ng-show="myForm.input.$error.pattern">
23274                Single word only!</span>
23275            </div>
23276            <code>text = {{example.text}}</code><br/>
23277            <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br/>
23278            <code>myForm.input.$error = {{myForm.input.$error}}</code><br/>
23279            <code>myForm.$valid = {{myForm.$valid}}</code><br/>
23280            <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br/>
23281           </form>
23282         </file>
23283         <file name="protractor.js" type="protractor">
23284           var text = element(by.binding('example.text'));
23285           var valid = element(by.binding('myForm.input.$valid'));
23286           var input = element(by.model('example.text'));
23287
23288           it('should initialize to model', function() {
23289             expect(text.getText()).toContain('guest');
23290             expect(valid.getText()).toContain('true');
23291           });
23292
23293           it('should be invalid if empty', function() {
23294             input.clear();
23295             input.sendKeys('');
23296
23297             expect(text.getText()).toEqual('text =');
23298             expect(valid.getText()).toContain('false');
23299           });
23300
23301           it('should be invalid if multi word', function() {
23302             input.clear();
23303             input.sendKeys('hello world');
23304
23305             expect(valid.getText()).toContain('false');
23306           });
23307         </file>
23308       </example>
23309    */
23310   'text': textInputType,
23311
23312     /**
23313      * @ngdoc input
23314      * @name input[date]
23315      *
23316      * @description
23317      * Input with date validation and transformation. In browsers that do not yet support
23318      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
23319      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
23320      * modern browsers do not yet support this input type, it is important to provide cues to users on the
23321      * expected input format via a placeholder or label.
23322      *
23323      * The model must always be a Date object, otherwise Angular will throw an error.
23324      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
23325      *
23326      * The timezone to be used to read/write the `Date` instance in the model can be defined using
23327      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
23328      *
23329      * @param {string} ngModel Assignable angular expression to data-bind to.
23330      * @param {string=} name Property name of the form under which the control is published.
23331      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
23332      *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
23333      *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
23334      *   constraint validation.
23335      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
23336      *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
23337      *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
23338      *   constraint validation.
23339      * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
23340      *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
23341      * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
23342      *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
23343      * @param {string=} required Sets `required` validation error key if the value is not entered.
23344      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23345      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23346      *    `required` when you want to data-bind to the `required` attribute.
23347      * @param {string=} ngChange Angular expression to be executed when input changes due to user
23348      *    interaction with the input element.
23349      *
23350      * @example
23351      <example name="date-input-directive" module="dateInputExample">
23352      <file name="index.html">
23353        <script>
23354           angular.module('dateInputExample', [])
23355             .controller('DateController', ['$scope', function($scope) {
23356               $scope.example = {
23357                 value: new Date(2013, 9, 22)
23358               };
23359             }]);
23360        </script>
23361        <form name="myForm" ng-controller="DateController as dateCtrl">
23362           <label for="exampleInput">Pick a date in 2013:</label>
23363           <input type="date" id="exampleInput" name="input" ng-model="example.value"
23364               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
23365           <div role="alert">
23366             <span class="error" ng-show="myForm.input.$error.required">
23367                 Required!</span>
23368             <span class="error" ng-show="myForm.input.$error.date">
23369                 Not a valid date!</span>
23370            </div>
23371            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
23372            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23373            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23374            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23375            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23376        </form>
23377      </file>
23378      <file name="protractor.js" type="protractor">
23379         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
23380         var valid = element(by.binding('myForm.input.$valid'));
23381
23382         // currently protractor/webdriver does not support
23383         // sending keys to all known HTML5 input controls
23384         // for various browsers (see https://github.com/angular/protractor/issues/562).
23385         function setInput(val) {
23386           // set the value of the element and force validation.
23387           var scr = "var ipt = document.getElementById('exampleInput'); " +
23388           "ipt.value = '" + val + "';" +
23389           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
23390           browser.executeScript(scr);
23391         }
23392
23393         it('should initialize to model', function() {
23394           expect(value.getText()).toContain('2013-10-22');
23395           expect(valid.getText()).toContain('myForm.input.$valid = true');
23396         });
23397
23398         it('should be invalid if empty', function() {
23399           setInput('');
23400           expect(value.getText()).toEqual('value =');
23401           expect(valid.getText()).toContain('myForm.input.$valid = false');
23402         });
23403
23404         it('should be invalid if over max', function() {
23405           setInput('2015-01-01');
23406           expect(value.getText()).toContain('');
23407           expect(valid.getText()).toContain('myForm.input.$valid = false');
23408         });
23409      </file>
23410      </example>
23411      */
23412   'date': createDateInputType('date', DATE_REGEXP,
23413          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
23414          'yyyy-MM-dd'),
23415
23416    /**
23417     * @ngdoc input
23418     * @name input[datetime-local]
23419     *
23420     * @description
23421     * Input with datetime validation and transformation. In browsers that do not yet support
23422     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
23423     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
23424     *
23425     * The model must always be a Date object, otherwise Angular will throw an error.
23426     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
23427     *
23428     * The timezone to be used to read/write the `Date` instance in the model can be defined using
23429     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
23430     *
23431     * @param {string} ngModel Assignable angular expression to data-bind to.
23432     * @param {string=} name Property name of the form under which the control is published.
23433     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
23434     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
23435     *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
23436     *   Note that `min` will also add native HTML5 constraint validation.
23437     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
23438     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
23439     *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
23440     *   Note that `max` will also add native HTML5 constraint validation.
23441     * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
23442     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
23443     * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
23444     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
23445     * @param {string=} required Sets `required` validation error key if the value is not entered.
23446     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23447     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23448     *    `required` when you want to data-bind to the `required` attribute.
23449     * @param {string=} ngChange Angular expression to be executed when input changes due to user
23450     *    interaction with the input element.
23451     *
23452     * @example
23453     <example name="datetimelocal-input-directive" module="dateExample">
23454     <file name="index.html">
23455       <script>
23456         angular.module('dateExample', [])
23457           .controller('DateController', ['$scope', function($scope) {
23458             $scope.example = {
23459               value: new Date(2010, 11, 28, 14, 57)
23460             };
23461           }]);
23462       </script>
23463       <form name="myForm" ng-controller="DateController as dateCtrl">
23464         <label for="exampleInput">Pick a date between in 2013:</label>
23465         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
23466             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
23467         <div role="alert">
23468           <span class="error" ng-show="myForm.input.$error.required">
23469               Required!</span>
23470           <span class="error" ng-show="myForm.input.$error.datetimelocal">
23471               Not a valid date!</span>
23472         </div>
23473         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
23474         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23475         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23476         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23477         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23478       </form>
23479     </file>
23480     <file name="protractor.js" type="protractor">
23481       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
23482       var valid = element(by.binding('myForm.input.$valid'));
23483
23484       // currently protractor/webdriver does not support
23485       // sending keys to all known HTML5 input controls
23486       // for various browsers (https://github.com/angular/protractor/issues/562).
23487       function setInput(val) {
23488         // set the value of the element and force validation.
23489         var scr = "var ipt = document.getElementById('exampleInput'); " +
23490         "ipt.value = '" + val + "';" +
23491         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
23492         browser.executeScript(scr);
23493       }
23494
23495       it('should initialize to model', function() {
23496         expect(value.getText()).toContain('2010-12-28T14:57:00');
23497         expect(valid.getText()).toContain('myForm.input.$valid = true');
23498       });
23499
23500       it('should be invalid if empty', function() {
23501         setInput('');
23502         expect(value.getText()).toEqual('value =');
23503         expect(valid.getText()).toContain('myForm.input.$valid = false');
23504       });
23505
23506       it('should be invalid if over max', function() {
23507         setInput('2015-01-01T23:59:00');
23508         expect(value.getText()).toContain('');
23509         expect(valid.getText()).toContain('myForm.input.$valid = false');
23510       });
23511     </file>
23512     </example>
23513     */
23514   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
23515       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
23516       'yyyy-MM-ddTHH:mm:ss.sss'),
23517
23518   /**
23519    * @ngdoc input
23520    * @name input[time]
23521    *
23522    * @description
23523    * Input with time validation and transformation. In browsers that do not yet support
23524    * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
23525    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
23526    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
23527    *
23528    * The model must always be a Date object, otherwise Angular will throw an error.
23529    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
23530    *
23531    * The timezone to be used to read/write the `Date` instance in the model can be defined using
23532    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
23533    *
23534    * @param {string} ngModel Assignable angular expression to data-bind to.
23535    * @param {string=} name Property name of the form under which the control is published.
23536    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
23537    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
23538    *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
23539    *   native HTML5 constraint validation.
23540    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
23541    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
23542    *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
23543    *   native HTML5 constraint validation.
23544    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
23545    *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
23546    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
23547    *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
23548    * @param {string=} required Sets `required` validation error key if the value is not entered.
23549    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23550    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23551    *    `required` when you want to data-bind to the `required` attribute.
23552    * @param {string=} ngChange Angular expression to be executed when input changes due to user
23553    *    interaction with the input element.
23554    *
23555    * @example
23556    <example name="time-input-directive" module="timeExample">
23557    <file name="index.html">
23558      <script>
23559       angular.module('timeExample', [])
23560         .controller('DateController', ['$scope', function($scope) {
23561           $scope.example = {
23562             value: new Date(1970, 0, 1, 14, 57, 0)
23563           };
23564         }]);
23565      </script>
23566      <form name="myForm" ng-controller="DateController as dateCtrl">
23567         <label for="exampleInput">Pick a time between 8am and 5pm:</label>
23568         <input type="time" id="exampleInput" name="input" ng-model="example.value"
23569             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
23570         <div role="alert">
23571           <span class="error" ng-show="myForm.input.$error.required">
23572               Required!</span>
23573           <span class="error" ng-show="myForm.input.$error.time">
23574               Not a valid date!</span>
23575         </div>
23576         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
23577         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23578         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23579         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23580         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23581      </form>
23582    </file>
23583    <file name="protractor.js" type="protractor">
23584       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
23585       var valid = element(by.binding('myForm.input.$valid'));
23586
23587       // currently protractor/webdriver does not support
23588       // sending keys to all known HTML5 input controls
23589       // for various browsers (https://github.com/angular/protractor/issues/562).
23590       function setInput(val) {
23591         // set the value of the element and force validation.
23592         var scr = "var ipt = document.getElementById('exampleInput'); " +
23593         "ipt.value = '" + val + "';" +
23594         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
23595         browser.executeScript(scr);
23596       }
23597
23598       it('should initialize to model', function() {
23599         expect(value.getText()).toContain('14:57:00');
23600         expect(valid.getText()).toContain('myForm.input.$valid = true');
23601       });
23602
23603       it('should be invalid if empty', function() {
23604         setInput('');
23605         expect(value.getText()).toEqual('value =');
23606         expect(valid.getText()).toContain('myForm.input.$valid = false');
23607       });
23608
23609       it('should be invalid if over max', function() {
23610         setInput('23:59:00');
23611         expect(value.getText()).toContain('');
23612         expect(valid.getText()).toContain('myForm.input.$valid = false');
23613       });
23614    </file>
23615    </example>
23616    */
23617   'time': createDateInputType('time', TIME_REGEXP,
23618       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
23619      'HH:mm:ss.sss'),
23620
23621    /**
23622     * @ngdoc input
23623     * @name input[week]
23624     *
23625     * @description
23626     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
23627     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
23628     * week format (yyyy-W##), for example: `2013-W02`.
23629     *
23630     * The model must always be a Date object, otherwise Angular will throw an error.
23631     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
23632     *
23633     * The timezone to be used to read/write the `Date` instance in the model can be defined using
23634     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
23635     *
23636     * @param {string} ngModel Assignable angular expression to data-bind to.
23637     * @param {string=} name Property name of the form under which the control is published.
23638     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
23639     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
23640     *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
23641     *   native HTML5 constraint validation.
23642     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
23643     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
23644     *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
23645     *   native HTML5 constraint validation.
23646     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
23647     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
23648     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
23649     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
23650     * @param {string=} required Sets `required` validation error key if the value is not entered.
23651     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23652     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23653     *    `required` when you want to data-bind to the `required` attribute.
23654     * @param {string=} ngChange Angular expression to be executed when input changes due to user
23655     *    interaction with the input element.
23656     *
23657     * @example
23658     <example name="week-input-directive" module="weekExample">
23659     <file name="index.html">
23660       <script>
23661       angular.module('weekExample', [])
23662         .controller('DateController', ['$scope', function($scope) {
23663           $scope.example = {
23664             value: new Date(2013, 0, 3)
23665           };
23666         }]);
23667       </script>
23668       <form name="myForm" ng-controller="DateController as dateCtrl">
23669         <label>Pick a date between in 2013:
23670           <input id="exampleInput" type="week" name="input" ng-model="example.value"
23671                  placeholder="YYYY-W##" min="2012-W32"
23672                  max="2013-W52" required />
23673         </label>
23674         <div role="alert">
23675           <span class="error" ng-show="myForm.input.$error.required">
23676               Required!</span>
23677           <span class="error" ng-show="myForm.input.$error.week">
23678               Not a valid date!</span>
23679         </div>
23680         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
23681         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23682         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23683         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23684         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23685       </form>
23686     </file>
23687     <file name="protractor.js" type="protractor">
23688       var value = element(by.binding('example.value | date: "yyyy-Www"'));
23689       var valid = element(by.binding('myForm.input.$valid'));
23690
23691       // currently protractor/webdriver does not support
23692       // sending keys to all known HTML5 input controls
23693       // for various browsers (https://github.com/angular/protractor/issues/562).
23694       function setInput(val) {
23695         // set the value of the element and force validation.
23696         var scr = "var ipt = document.getElementById('exampleInput'); " +
23697         "ipt.value = '" + val + "';" +
23698         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
23699         browser.executeScript(scr);
23700       }
23701
23702       it('should initialize to model', function() {
23703         expect(value.getText()).toContain('2013-W01');
23704         expect(valid.getText()).toContain('myForm.input.$valid = true');
23705       });
23706
23707       it('should be invalid if empty', function() {
23708         setInput('');
23709         expect(value.getText()).toEqual('value =');
23710         expect(valid.getText()).toContain('myForm.input.$valid = false');
23711       });
23712
23713       it('should be invalid if over max', function() {
23714         setInput('2015-W01');
23715         expect(value.getText()).toContain('');
23716         expect(valid.getText()).toContain('myForm.input.$valid = false');
23717       });
23718     </file>
23719     </example>
23720     */
23721   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
23722
23723   /**
23724    * @ngdoc input
23725    * @name input[month]
23726    *
23727    * @description
23728    * Input with month validation and transformation. In browsers that do not yet support
23729    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
23730    * month format (yyyy-MM), for example: `2009-01`.
23731    *
23732    * The model must always be a Date object, otherwise Angular will throw an error.
23733    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
23734    * If the model is not set to the first of the month, the next view to model update will set it
23735    * to the first of the month.
23736    *
23737    * The timezone to be used to read/write the `Date` instance in the model can be defined using
23738    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
23739    *
23740    * @param {string} ngModel Assignable angular expression to data-bind to.
23741    * @param {string=} name Property name of the form under which the control is published.
23742    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
23743    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
23744    *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
23745    *   native HTML5 constraint validation.
23746    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
23747    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
23748    *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
23749    *   native HTML5 constraint validation.
23750    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
23751    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
23752    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
23753    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
23754
23755    * @param {string=} required Sets `required` validation error key if the value is not entered.
23756    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23757    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23758    *    `required` when you want to data-bind to the `required` attribute.
23759    * @param {string=} ngChange Angular expression to be executed when input changes due to user
23760    *    interaction with the input element.
23761    *
23762    * @example
23763    <example name="month-input-directive" module="monthExample">
23764    <file name="index.html">
23765      <script>
23766       angular.module('monthExample', [])
23767         .controller('DateController', ['$scope', function($scope) {
23768           $scope.example = {
23769             value: new Date(2013, 9, 1)
23770           };
23771         }]);
23772      </script>
23773      <form name="myForm" ng-controller="DateController as dateCtrl">
23774        <label for="exampleInput">Pick a month in 2013:</label>
23775        <input id="exampleInput" type="month" name="input" ng-model="example.value"
23776           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
23777        <div role="alert">
23778          <span class="error" ng-show="myForm.input.$error.required">
23779             Required!</span>
23780          <span class="error" ng-show="myForm.input.$error.month">
23781             Not a valid month!</span>
23782        </div>
23783        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
23784        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23785        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23786        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23787        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23788      </form>
23789    </file>
23790    <file name="protractor.js" type="protractor">
23791       var value = element(by.binding('example.value | date: "yyyy-MM"'));
23792       var valid = element(by.binding('myForm.input.$valid'));
23793
23794       // currently protractor/webdriver does not support
23795       // sending keys to all known HTML5 input controls
23796       // for various browsers (https://github.com/angular/protractor/issues/562).
23797       function setInput(val) {
23798         // set the value of the element and force validation.
23799         var scr = "var ipt = document.getElementById('exampleInput'); " +
23800         "ipt.value = '" + val + "';" +
23801         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
23802         browser.executeScript(scr);
23803       }
23804
23805       it('should initialize to model', function() {
23806         expect(value.getText()).toContain('2013-10');
23807         expect(valid.getText()).toContain('myForm.input.$valid = true');
23808       });
23809
23810       it('should be invalid if empty', function() {
23811         setInput('');
23812         expect(value.getText()).toEqual('value =');
23813         expect(valid.getText()).toContain('myForm.input.$valid = false');
23814       });
23815
23816       it('should be invalid if over max', function() {
23817         setInput('2015-01');
23818         expect(value.getText()).toContain('');
23819         expect(valid.getText()).toContain('myForm.input.$valid = false');
23820       });
23821    </file>
23822    </example>
23823    */
23824   'month': createDateInputType('month', MONTH_REGEXP,
23825      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
23826      'yyyy-MM'),
23827
23828   /**
23829    * @ngdoc input
23830    * @name input[number]
23831    *
23832    * @description
23833    * Text input with number validation and transformation. Sets the `number` validation
23834    * error if not a valid number.
23835    *
23836    * <div class="alert alert-warning">
23837    * The model must always be of type `number` otherwise Angular will throw an error.
23838    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
23839    * error docs for more information and an example of how to convert your model if necessary.
23840    * </div>
23841    *
23842    * ## Issues with HTML5 constraint validation
23843    *
23844    * In browsers that follow the
23845    * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
23846    * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
23847    * If a non-number is entered in the input, the browser will report the value as an empty string,
23848    * which means the view / model values in `ngModel` and subsequently the scope value
23849    * will also be an empty string.
23850    *
23851    *
23852    * @param {string} ngModel Assignable angular expression to data-bind to.
23853    * @param {string=} name Property name of the form under which the control is published.
23854    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
23855    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
23856    * @param {string=} required Sets `required` validation error key if the value is not entered.
23857    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23858    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23859    *    `required` when you want to data-bind to the `required` attribute.
23860    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
23861    *    minlength.
23862    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
23863    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
23864    *    any length.
23865    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
23866    *    that contains the regular expression body that will be converted to a regular expression
23867    *    as in the ngPattern directive.
23868    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
23869    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
23870    *    If the expression evaluates to a RegExp object, then this is used directly.
23871    *    If the expression evaluates to a string, then it will be converted to a RegExp
23872    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
23873    *    `new RegExp('^abc$')`.<br />
23874    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
23875    *    start at the index of the last search's match, thus not taking the whole input value into
23876    *    account.
23877    * @param {string=} ngChange Angular expression to be executed when input changes due to user
23878    *    interaction with the input element.
23879    *
23880    * @example
23881       <example name="number-input-directive" module="numberExample">
23882         <file name="index.html">
23883          <script>
23884            angular.module('numberExample', [])
23885              .controller('ExampleController', ['$scope', function($scope) {
23886                $scope.example = {
23887                  value: 12
23888                };
23889              }]);
23890          </script>
23891          <form name="myForm" ng-controller="ExampleController">
23892            <label>Number:
23893              <input type="number" name="input" ng-model="example.value"
23894                     min="0" max="99" required>
23895           </label>
23896            <div role="alert">
23897              <span class="error" ng-show="myForm.input.$error.required">
23898                Required!</span>
23899              <span class="error" ng-show="myForm.input.$error.number">
23900                Not valid number!</span>
23901            </div>
23902            <tt>value = {{example.value}}</tt><br/>
23903            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
23904            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
23905            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
23906            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
23907           </form>
23908         </file>
23909         <file name="protractor.js" type="protractor">
23910           var value = element(by.binding('example.value'));
23911           var valid = element(by.binding('myForm.input.$valid'));
23912           var input = element(by.model('example.value'));
23913
23914           it('should initialize to model', function() {
23915             expect(value.getText()).toContain('12');
23916             expect(valid.getText()).toContain('true');
23917           });
23918
23919           it('should be invalid if empty', function() {
23920             input.clear();
23921             input.sendKeys('');
23922             expect(value.getText()).toEqual('value =');
23923             expect(valid.getText()).toContain('false');
23924           });
23925
23926           it('should be invalid if over max', function() {
23927             input.clear();
23928             input.sendKeys('123');
23929             expect(value.getText()).toEqual('value =');
23930             expect(valid.getText()).toContain('false');
23931           });
23932         </file>
23933       </example>
23934    */
23935   'number': numberInputType,
23936
23937
23938   /**
23939    * @ngdoc input
23940    * @name input[url]
23941    *
23942    * @description
23943    * Text input with URL validation. Sets the `url` validation error key if the content is not a
23944    * valid URL.
23945    *
23946    * <div class="alert alert-warning">
23947    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
23948    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
23949    * the built-in validators (see the {@link guide/forms Forms guide})
23950    * </div>
23951    *
23952    * @param {string} ngModel Assignable angular expression to data-bind to.
23953    * @param {string=} name Property name of the form under which the control is published.
23954    * @param {string=} required Sets `required` validation error key if the value is not entered.
23955    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23956    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23957    *    `required` when you want to data-bind to the `required` attribute.
23958    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
23959    *    minlength.
23960    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
23961    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
23962    *    any length.
23963    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
23964    *    that contains the regular expression body that will be converted to a regular expression
23965    *    as in the ngPattern directive.
23966    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
23967    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
23968    *    If the expression evaluates to a RegExp object, then this is used directly.
23969    *    If the expression evaluates to a string, then it will be converted to a RegExp
23970    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
23971    *    `new RegExp('^abc$')`.<br />
23972    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
23973    *    start at the index of the last search's match, thus not taking the whole input value into
23974    *    account.
23975    * @param {string=} ngChange Angular expression to be executed when input changes due to user
23976    *    interaction with the input element.
23977    *
23978    * @example
23979       <example name="url-input-directive" module="urlExample">
23980         <file name="index.html">
23981          <script>
23982            angular.module('urlExample', [])
23983              .controller('ExampleController', ['$scope', function($scope) {
23984                $scope.url = {
23985                  text: 'http://google.com'
23986                };
23987              }]);
23988          </script>
23989          <form name="myForm" ng-controller="ExampleController">
23990            <label>URL:
23991              <input type="url" name="input" ng-model="url.text" required>
23992            <label>
23993            <div role="alert">
23994              <span class="error" ng-show="myForm.input.$error.required">
23995                Required!</span>
23996              <span class="error" ng-show="myForm.input.$error.url">
23997                Not valid url!</span>
23998            </div>
23999            <tt>text = {{url.text}}</tt><br/>
24000            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
24001            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
24002            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24003            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24004            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
24005           </form>
24006         </file>
24007         <file name="protractor.js" type="protractor">
24008           var text = element(by.binding('url.text'));
24009           var valid = element(by.binding('myForm.input.$valid'));
24010           var input = element(by.model('url.text'));
24011
24012           it('should initialize to model', function() {
24013             expect(text.getText()).toContain('http://google.com');
24014             expect(valid.getText()).toContain('true');
24015           });
24016
24017           it('should be invalid if empty', function() {
24018             input.clear();
24019             input.sendKeys('');
24020
24021             expect(text.getText()).toEqual('text =');
24022             expect(valid.getText()).toContain('false');
24023           });
24024
24025           it('should be invalid if not url', function() {
24026             input.clear();
24027             input.sendKeys('box');
24028
24029             expect(valid.getText()).toContain('false');
24030           });
24031         </file>
24032       </example>
24033    */
24034   'url': urlInputType,
24035
24036
24037   /**
24038    * @ngdoc input
24039    * @name input[email]
24040    *
24041    * @description
24042    * Text input with email validation. Sets the `email` validation error key if not a valid email
24043    * address.
24044    *
24045    * <div class="alert alert-warning">
24046    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
24047    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
24048    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
24049    * </div>
24050    *
24051    * @param {string} ngModel Assignable angular expression to data-bind to.
24052    * @param {string=} name Property name of the form under which the control is published.
24053    * @param {string=} required Sets `required` validation error key if the value is not entered.
24054    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
24055    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
24056    *    `required` when you want to data-bind to the `required` attribute.
24057    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
24058    *    minlength.
24059    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
24060    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
24061    *    any length.
24062    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
24063    *    that contains the regular expression body that will be converted to a regular expression
24064    *    as in the ngPattern directive.
24065    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
24066    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
24067    *    If the expression evaluates to a RegExp object, then this is used directly.
24068    *    If the expression evaluates to a string, then it will be converted to a RegExp
24069    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
24070    *    `new RegExp('^abc$')`.<br />
24071    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
24072    *    start at the index of the last search's match, thus not taking the whole input value into
24073    *    account.
24074    * @param {string=} ngChange Angular expression to be executed when input changes due to user
24075    *    interaction with the input element.
24076    *
24077    * @example
24078       <example name="email-input-directive" module="emailExample">
24079         <file name="index.html">
24080          <script>
24081            angular.module('emailExample', [])
24082              .controller('ExampleController', ['$scope', function($scope) {
24083                $scope.email = {
24084                  text: 'me@example.com'
24085                };
24086              }]);
24087          </script>
24088            <form name="myForm" ng-controller="ExampleController">
24089              <label>Email:
24090                <input type="email" name="input" ng-model="email.text" required>
24091              </label>
24092              <div role="alert">
24093                <span class="error" ng-show="myForm.input.$error.required">
24094                  Required!</span>
24095                <span class="error" ng-show="myForm.input.$error.email">
24096                  Not valid email!</span>
24097              </div>
24098              <tt>text = {{email.text}}</tt><br/>
24099              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
24100              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
24101              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24102              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24103              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
24104            </form>
24105          </file>
24106         <file name="protractor.js" type="protractor">
24107           var text = element(by.binding('email.text'));
24108           var valid = element(by.binding('myForm.input.$valid'));
24109           var input = element(by.model('email.text'));
24110
24111           it('should initialize to model', function() {
24112             expect(text.getText()).toContain('me@example.com');
24113             expect(valid.getText()).toContain('true');
24114           });
24115
24116           it('should be invalid if empty', function() {
24117             input.clear();
24118             input.sendKeys('');
24119             expect(text.getText()).toEqual('text =');
24120             expect(valid.getText()).toContain('false');
24121           });
24122
24123           it('should be invalid if not email', function() {
24124             input.clear();
24125             input.sendKeys('xxx');
24126
24127             expect(valid.getText()).toContain('false');
24128           });
24129         </file>
24130       </example>
24131    */
24132   'email': emailInputType,
24133
24134
24135   /**
24136    * @ngdoc input
24137    * @name input[radio]
24138    *
24139    * @description
24140    * HTML radio button.
24141    *
24142    * @param {string} ngModel Assignable angular expression to data-bind to.
24143    * @param {string} value The value to which the `ngModel` expression should be set when selected.
24144    *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
24145    *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
24146    * @param {string=} name Property name of the form under which the control is published.
24147    * @param {string=} ngChange Angular expression to be executed when input changes due to user
24148    *    interaction with the input element.
24149    * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
24150    *    is selected. Should be used instead of the `value` attribute if you need
24151    *    a non-string `ngModel` (`boolean`, `array`, ...).
24152    *
24153    * @example
24154       <example name="radio-input-directive" module="radioExample">
24155         <file name="index.html">
24156          <script>
24157            angular.module('radioExample', [])
24158              .controller('ExampleController', ['$scope', function($scope) {
24159                $scope.color = {
24160                  name: 'blue'
24161                };
24162                $scope.specialValue = {
24163                  "id": "12345",
24164                  "value": "green"
24165                };
24166              }]);
24167          </script>
24168          <form name="myForm" ng-controller="ExampleController">
24169            <label>
24170              <input type="radio" ng-model="color.name" value="red">
24171              Red
24172            </label><br/>
24173            <label>
24174              <input type="radio" ng-model="color.name" ng-value="specialValue">
24175              Green
24176            </label><br/>
24177            <label>
24178              <input type="radio" ng-model="color.name" value="blue">
24179              Blue
24180            </label><br/>
24181            <tt>color = {{color.name | json}}</tt><br/>
24182           </form>
24183           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
24184         </file>
24185         <file name="protractor.js" type="protractor">
24186           it('should change state', function() {
24187             var inputs = element.all(by.model('color.name'));
24188             var color = element(by.binding('color.name'));
24189
24190             expect(color.getText()).toContain('blue');
24191
24192             inputs.get(0).click();
24193             expect(color.getText()).toContain('red');
24194
24195             inputs.get(1).click();
24196             expect(color.getText()).toContain('green');
24197           });
24198         </file>
24199       </example>
24200    */
24201   'radio': radioInputType,
24202
24203   /**
24204    * @ngdoc input
24205    * @name input[range]
24206    *
24207    * @description
24208    * Native range input with validation and transformation.
24209    *
24210    * <div class="alert alert-warning">
24211    *   <p>
24212    *     In v1.5.9+, in order to avoid interfering with already existing, custom directives for
24213    *     `input[range]`, you need to let Angular know that you want to enable its built-in support.
24214    *     You can do this by adding the `ng-input-range` attribute to the input element. E.g.:
24215    *     `<input type="range" ng-input-range ... />`
24216    *   </p><br />
24217    *   <p>
24218    *     Input elements without the `ng-input-range` attibute will continue to be treated the same
24219    *     as in previous versions (e.g. their model value will be a string not a number and Angular
24220    *     will not take `min`/`max`/`step` attributes and properties into account).
24221    *   </p><br />
24222    *   <p>
24223    *     **Note:** From v1.6.x onwards, the support for `input[range]` will be always enabled and
24224    *     the `ng-input-range` attribute will have no effect.
24225    *   </p><br />
24226    *   <p>
24227    *     This documentation page refers to elements which have the built-in support enabled; i.e.
24228    *     elements _with_ the `ng-input-range` attribute.
24229    *   </p>
24230    * </div>
24231    *
24232    * The model for the range input must always be a `Number`.
24233    *
24234    * IE9 and other browsers that do not support the `range` type fall back
24235    * to a text input without any default values for `min`, `max` and `step`. Model binding,
24236    * validation and number parsing are nevertheless supported.
24237    *
24238    * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]`
24239    * in a way that never allows the input to hold an invalid value. That means:
24240    * - any non-numerical value is set to `(max + min) / 2`.
24241    * - any numerical value that is less than the current min val, or greater than the current max val
24242    * is set to the min / max val respectively.
24243    * - additionally, the current `step` is respected, so the nearest value that satisfies a step
24244    * is used.
24245    *
24246    * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range))
24247    * for more info.
24248    *
24249    * This has the following consequences for Angular:
24250    *
24251    * Since the element value should always reflect the current model value, a range input
24252    * will set the bound ngModel expression to the value that the browser has set for the
24253    * input element. For example, in the following input `<input type="range" ng-input-range ng-model="model.value">`,
24254    * if the application sets `model.value = null`, the browser will set the input to `'50'`.
24255    * Angular will then set the model to `50`, to prevent input and model value being out of sync.
24256    *
24257    * That means the model for range will immediately be set to `50` after `ngModel` has been
24258    * initialized. It also means a range input can never have the required error.
24259    *
24260    * This does not only affect changes to the model value, but also to the values of the `min`,
24261    * `max`, and `step` attributes. When these change in a way that will cause the browser to modify
24262    * the input value, Angular will also update the model value.
24263    *
24264    * Automatic value adjustment also means that a range input element can never have the `required`,
24265    * `min`, or `max` errors.
24266    *
24267    * However, `step` is currently only fully implemented by Firefox. Other browsers have problems
24268    * when the step value changes dynamically - they do not adjust the element value correctly, but
24269    * instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step`
24270    * error on the input, and set the model to `undefined`.
24271    *
24272    * Note that `input[range]` is not compatible with `ngMax`, `ngMin`, and `ngStep`, because they do
24273    * not set the `min` and `max` attributes, which means that the browser won't automatically adjust
24274    * the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
24275    *
24276    * @param           ngInputRange The presense of this attribute enables the built-in support for
24277    *                  `input[range]`.
24278    * @param {string}  ngModel Assignable angular expression to data-bind to.
24279    * @param {string=} name Property name of the form under which the control is published.
24280    * @param {string=} min Sets the `min` validation to ensure that the value entered is greater
24281    *                  than `min`. Can be interpolated.
24282    * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`.
24283    *                  Can be interpolated.
24284    * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step`
24285    *                  Can be interpolated.
24286    * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due
24287    *                  to user interaction with the input element.
24288    * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the
24289    *                      element. **Note** : `ngChecked` should not be used alongside `ngModel`.
24290    *                      Checkout {@link ng.directive:ngChecked ngChecked} for usage.
24291    *
24292    * @example
24293       <example name="range-input-directive" module="rangeExample">
24294         <file name="index.html">
24295           <script>
24296             angular.module('rangeExample', [])
24297               .controller('ExampleController', ['$scope', function($scope) {
24298                 $scope.value = 75;
24299                 $scope.min = 10;
24300                 $scope.max = 90;
24301               }]);
24302           </script>
24303           <form name="myForm" ng-controller="ExampleController">
24304
24305             Model as range: <input type="range" ng-input-range name="range" ng-model="value" min="{{min}}"  max="{{max}}">
24306             <hr>
24307             Model as number: <input type="number" ng-model="value"><br>
24308             Min: <input type="number" ng-model="min"><br>
24309             Max: <input type="number" ng-model="max"><br>
24310             value = <code>{{value}}</code><br/>
24311             myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
24312             myForm.range.$error = <code>{{myForm.range.$error}}</code>
24313           </form>
24314         </file>
24315       </example>
24316
24317    * ## Range Input with ngMin & ngMax attributes
24318
24319    * @example
24320       <example name="range-input-directive-ng" module="rangeExample">
24321         <file name="index.html">
24322           <script>
24323             angular.module('rangeExample', [])
24324               .controller('ExampleController', ['$scope', function($scope) {
24325                 $scope.value = 75;
24326                 $scope.min = 10;
24327                 $scope.max = 90;
24328               }]);
24329           </script>
24330           <form name="myForm" ng-controller="ExampleController">
24331             Model as range: <input type="range" ng-input-range name="range" ng-model="value" ng-min="min" ng-max="max">
24332             <hr>
24333             Model as number: <input type="number" ng-model="value"><br>
24334             Min: <input type="number" ng-model="min"><br>
24335             Max: <input type="number" ng-model="max"><br>
24336             value = <code>{{value}}</code><br/>
24337             myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
24338             myForm.range.$error = <code>{{myForm.range.$error}}</code>
24339           </form>
24340         </file>
24341       </example>
24342
24343    */
24344   'range': rangeInputType,
24345
24346   /**
24347    * @ngdoc input
24348    * @name input[checkbox]
24349    *
24350    * @description
24351    * HTML checkbox.
24352    *
24353    * @param {string} ngModel Assignable angular expression to data-bind to.
24354    * @param {string=} name Property name of the form under which the control is published.
24355    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
24356    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
24357    * @param {string=} ngChange Angular expression to be executed when input changes due to user
24358    *    interaction with the input element.
24359    *
24360    * @example
24361       <example name="checkbox-input-directive" module="checkboxExample">
24362         <file name="index.html">
24363          <script>
24364            angular.module('checkboxExample', [])
24365              .controller('ExampleController', ['$scope', function($scope) {
24366                $scope.checkboxModel = {
24367                 value1 : true,
24368                 value2 : 'YES'
24369               };
24370              }]);
24371          </script>
24372          <form name="myForm" ng-controller="ExampleController">
24373            <label>Value1:
24374              <input type="checkbox" ng-model="checkboxModel.value1">
24375            </label><br/>
24376            <label>Value2:
24377              <input type="checkbox" ng-model="checkboxModel.value2"
24378                     ng-true-value="'YES'" ng-false-value="'NO'">
24379             </label><br/>
24380            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
24381            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
24382           </form>
24383         </file>
24384         <file name="protractor.js" type="protractor">
24385           it('should change state', function() {
24386             var value1 = element(by.binding('checkboxModel.value1'));
24387             var value2 = element(by.binding('checkboxModel.value2'));
24388
24389             expect(value1.getText()).toContain('true');
24390             expect(value2.getText()).toContain('YES');
24391
24392             element(by.model('checkboxModel.value1')).click();
24393             element(by.model('checkboxModel.value2')).click();
24394
24395             expect(value1.getText()).toContain('false');
24396             expect(value2.getText()).toContain('NO');
24397           });
24398         </file>
24399       </example>
24400    */
24401   'checkbox': checkboxInputType,
24402
24403   'hidden': noop,
24404   'button': noop,
24405   'submit': noop,
24406   'reset': noop,
24407   'file': noop
24408 };
24409
24410 function stringBasedInputType(ctrl) {
24411   ctrl.$formatters.push(function(value) {
24412     return ctrl.$isEmpty(value) ? value : value.toString();
24413   });
24414 }
24415
24416 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24417   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24418   stringBasedInputType(ctrl);
24419 }
24420
24421 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24422   var type = lowercase(element[0].type);
24423
24424   // In composition mode, users are still inputting intermediate text buffer,
24425   // hold the listener until composition is done.
24426   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
24427   if (!$sniffer.android) {
24428     var composing = false;
24429
24430     element.on('compositionstart', function() {
24431       composing = true;
24432     });
24433
24434     element.on('compositionend', function() {
24435       composing = false;
24436       listener();
24437     });
24438   }
24439
24440   var timeout;
24441
24442   var listener = function(ev) {
24443     if (timeout) {
24444       $browser.defer.cancel(timeout);
24445       timeout = null;
24446     }
24447     if (composing) return;
24448     var value = element.val(),
24449         event = ev && ev.type;
24450
24451     // By default we will trim the value
24452     // If the attribute ng-trim exists we will avoid trimming
24453     // If input type is 'password', the value is never trimmed
24454     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
24455       value = trim(value);
24456     }
24457
24458     // If a control is suffering from bad input (due to native validators), browsers discard its
24459     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
24460     // control's value is the same empty value twice in a row.
24461     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
24462       ctrl.$setViewValue(value, event);
24463     }
24464   };
24465
24466   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
24467   // input event on backspace, delete or cut
24468   if ($sniffer.hasEvent('input')) {
24469     element.on('input', listener);
24470   } else {
24471     var deferListener = function(ev, input, origValue) {
24472       if (!timeout) {
24473         timeout = $browser.defer(function() {
24474           timeout = null;
24475           if (!input || input.value !== origValue) {
24476             listener(ev);
24477           }
24478         });
24479       }
24480     };
24481
24482     element.on('keydown', /** @this */ function(event) {
24483       var key = event.keyCode;
24484
24485       // ignore
24486       //    command            modifiers                   arrows
24487       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
24488
24489       deferListener(event, this, this.value);
24490     });
24491
24492     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
24493     if ($sniffer.hasEvent('paste')) {
24494       element.on('paste cut', deferListener);
24495     }
24496   }
24497
24498   // if user paste into input using mouse on older browser
24499   // or form autocomplete on newer browser, we need "change" event to catch it
24500   element.on('change', listener);
24501
24502   // Some native input types (date-family) have the ability to change validity without
24503   // firing any input/change events.
24504   // For these event types, when native validators are present and the browser supports the type,
24505   // check for validity changes on various DOM events.
24506   if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
24507     element.on(PARTIAL_VALIDATION_EVENTS, /** @this */ function(ev) {
24508       if (!timeout) {
24509         var validity = this[VALIDITY_STATE_PROPERTY];
24510         var origBadInput = validity.badInput;
24511         var origTypeMismatch = validity.typeMismatch;
24512         timeout = $browser.defer(function() {
24513           timeout = null;
24514           if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
24515             listener(ev);
24516           }
24517         });
24518       }
24519     });
24520   }
24521
24522   ctrl.$render = function() {
24523     // Workaround for Firefox validation #12102.
24524     var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
24525     if (element.val() !== value) {
24526       element.val(value);
24527     }
24528   };
24529 }
24530
24531 function weekParser(isoWeek, existingDate) {
24532   if (isDate(isoWeek)) {
24533     return isoWeek;
24534   }
24535
24536   if (isString(isoWeek)) {
24537     WEEK_REGEXP.lastIndex = 0;
24538     var parts = WEEK_REGEXP.exec(isoWeek);
24539     if (parts) {
24540       var year = +parts[1],
24541           week = +parts[2],
24542           hours = 0,
24543           minutes = 0,
24544           seconds = 0,
24545           milliseconds = 0,
24546           firstThurs = getFirstThursdayOfYear(year),
24547           addDays = (week - 1) * 7;
24548
24549       if (existingDate) {
24550         hours = existingDate.getHours();
24551         minutes = existingDate.getMinutes();
24552         seconds = existingDate.getSeconds();
24553         milliseconds = existingDate.getMilliseconds();
24554       }
24555
24556       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
24557     }
24558   }
24559
24560   return NaN;
24561 }
24562
24563 function createDateParser(regexp, mapping) {
24564   return function(iso, date) {
24565     var parts, map;
24566
24567     if (isDate(iso)) {
24568       return iso;
24569     }
24570
24571     if (isString(iso)) {
24572       // When a date is JSON'ified to wraps itself inside of an extra
24573       // set of double quotes. This makes the date parsing code unable
24574       // to match the date string and parse it as a date.
24575       if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') {
24576         iso = iso.substring(1, iso.length - 1);
24577       }
24578       if (ISO_DATE_REGEXP.test(iso)) {
24579         return new Date(iso);
24580       }
24581       regexp.lastIndex = 0;
24582       parts = regexp.exec(iso);
24583
24584       if (parts) {
24585         parts.shift();
24586         if (date) {
24587           map = {
24588             yyyy: date.getFullYear(),
24589             MM: date.getMonth() + 1,
24590             dd: date.getDate(),
24591             HH: date.getHours(),
24592             mm: date.getMinutes(),
24593             ss: date.getSeconds(),
24594             sss: date.getMilliseconds() / 1000
24595           };
24596         } else {
24597           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
24598         }
24599
24600         forEach(parts, function(part, index) {
24601           if (index < mapping.length) {
24602             map[mapping[index]] = +part;
24603           }
24604         });
24605         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
24606       }
24607     }
24608
24609     return NaN;
24610   };
24611 }
24612
24613 function createDateInputType(type, regexp, parseDate, format) {
24614   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
24615     badInputChecker(scope, element, attr, ctrl);
24616     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24617     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
24618     var previousDate;
24619
24620     ctrl.$$parserName = type;
24621     ctrl.$parsers.push(function(value) {
24622       if (ctrl.$isEmpty(value)) return null;
24623       if (regexp.test(value)) {
24624         // Note: We cannot read ctrl.$modelValue, as there might be a different
24625         // parser/formatter in the processing chain so that the model
24626         // contains some different data format!
24627         var parsedDate = parseDate(value, previousDate);
24628         if (timezone) {
24629           parsedDate = convertTimezoneToLocal(parsedDate, timezone);
24630         }
24631         return parsedDate;
24632       }
24633       return undefined;
24634     });
24635
24636     ctrl.$formatters.push(function(value) {
24637       if (value && !isDate(value)) {
24638         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
24639       }
24640       if (isValidDate(value)) {
24641         previousDate = value;
24642         if (previousDate && timezone) {
24643           previousDate = convertTimezoneToLocal(previousDate, timezone, true);
24644         }
24645         return $filter('date')(value, format, timezone);
24646       } else {
24647         previousDate = null;
24648         return '';
24649       }
24650     });
24651
24652     if (isDefined(attr.min) || attr.ngMin) {
24653       var minVal;
24654       ctrl.$validators.min = function(value) {
24655         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
24656       };
24657       attr.$observe('min', function(val) {
24658         minVal = parseObservedDateValue(val);
24659         ctrl.$validate();
24660       });
24661     }
24662
24663     if (isDefined(attr.max) || attr.ngMax) {
24664       var maxVal;
24665       ctrl.$validators.max = function(value) {
24666         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
24667       };
24668       attr.$observe('max', function(val) {
24669         maxVal = parseObservedDateValue(val);
24670         ctrl.$validate();
24671       });
24672     }
24673
24674     function isValidDate(value) {
24675       // Invalid Date: getTime() returns NaN
24676       return value && !(value.getTime && value.getTime() !== value.getTime());
24677     }
24678
24679     function parseObservedDateValue(val) {
24680       return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
24681     }
24682   };
24683 }
24684
24685 function badInputChecker(scope, element, attr, ctrl) {
24686   var node = element[0];
24687   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
24688   if (nativeValidation) {
24689     ctrl.$parsers.push(function(value) {
24690       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
24691       return validity.badInput || validity.typeMismatch ? undefined : value;
24692     });
24693   }
24694 }
24695
24696 function numberFormatterParser(ctrl) {
24697   ctrl.$$parserName = 'number';
24698   ctrl.$parsers.push(function(value) {
24699     if (ctrl.$isEmpty(value))      return null;
24700     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
24701     return undefined;
24702   });
24703
24704   ctrl.$formatters.push(function(value) {
24705     if (!ctrl.$isEmpty(value)) {
24706       if (!isNumber(value)) {
24707         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
24708       }
24709       value = value.toString();
24710     }
24711     return value;
24712   });
24713 }
24714
24715 function parseNumberAttrVal(val) {
24716   if (isDefined(val) && !isNumber(val)) {
24717     val = parseFloat(val);
24718   }
24719   return !isNumberNaN(val) ? val : undefined;
24720 }
24721
24722 function isNumberInteger(num) {
24723   // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066
24724   // (minus the assumption that `num` is a number)
24725
24726   // eslint-disable-next-line no-bitwise
24727   return (num | 0) === num;
24728 }
24729
24730 function countDecimals(num) {
24731   var numString = num.toString();
24732   var decimalSymbolIndex = numString.indexOf('.');
24733
24734   if (decimalSymbolIndex === -1) {
24735     if (-1 < num && num < 1) {
24736       // It may be in the exponential notation format (`1e-X`)
24737       var match = /e-(\d+)$/.exec(numString);
24738
24739       if (match) {
24740         return Number(match[1]);
24741       }
24742     }
24743
24744     return 0;
24745   }
24746
24747   return numString.length - decimalSymbolIndex - 1;
24748 }
24749
24750 function isValidForStep(viewValue, stepBase, step) {
24751   // At this point `stepBase` and `step` are expected to be non-NaN values
24752   // and `viewValue` is expected to be a valid stringified number.
24753   var value = Number(viewValue);
24754
24755   // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
24756   // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
24757   if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
24758     var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
24759     var multiplier = Math.pow(10, decimalCount);
24760
24761     value = value * multiplier;
24762     stepBase = stepBase * multiplier;
24763     step = step * multiplier;
24764   }
24765
24766   return (value - stepBase) % step === 0;
24767 }
24768
24769 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24770   badInputChecker(scope, element, attr, ctrl);
24771   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24772   numberFormatterParser(ctrl);
24773
24774   var minVal;
24775   var maxVal;
24776
24777   if (isDefined(attr.min) || attr.ngMin) {
24778     ctrl.$validators.min = function(value) {
24779       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
24780     };
24781
24782     attr.$observe('min', function(val) {
24783       minVal = parseNumberAttrVal(val);
24784       // TODO(matsko): implement validateLater to reduce number of validations
24785       ctrl.$validate();
24786     });
24787   }
24788
24789   if (isDefined(attr.max) || attr.ngMax) {
24790     ctrl.$validators.max = function(value) {
24791       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
24792     };
24793
24794     attr.$observe('max', function(val) {
24795       maxVal = parseNumberAttrVal(val);
24796       // TODO(matsko): implement validateLater to reduce number of validations
24797       ctrl.$validate();
24798     });
24799   }
24800 }
24801
24802 function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24803   badInputChecker(scope, element, attr, ctrl);
24804   numberFormatterParser(ctrl);
24805   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24806
24807   var supportsRange = ctrl.$$hasNativeValidators && element[0].type === 'range',
24808       minVal = supportsRange ? 0 : undefined,
24809       maxVal = supportsRange ? 100 : undefined,
24810       stepVal = supportsRange ? 1 : undefined,
24811       validity = element[0].validity,
24812       hasMinAttr = isDefined(attr.min),
24813       hasMaxAttr = isDefined(attr.max),
24814       hasStepAttr = isDefined(attr.step);
24815
24816   var originalRender = ctrl.$render;
24817
24818   ctrl.$render = supportsRange && isDefined(validity.rangeUnderflow) && isDefined(validity.rangeOverflow) ?
24819     //Browsers that implement range will set these values automatically, but reading the adjusted values after
24820     //$render would cause the min / max validators to be applied with the wrong value
24821     function rangeRender() {
24822       originalRender();
24823       ctrl.$setViewValue(element.val());
24824     } :
24825     originalRender;
24826
24827   if (hasMinAttr) {
24828     ctrl.$validators.min = supportsRange ?
24829       // Since all browsers set the input to a valid value, we don't need to check validity
24830       function noopMinValidator() { return true; } :
24831       // non-support browsers validate the min val
24832       function minValidator(modelValue, viewValue) {
24833         return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal;
24834       };
24835
24836     setInitialValueAndObserver('min', minChange);
24837   }
24838
24839   if (hasMaxAttr) {
24840     ctrl.$validators.max = supportsRange ?
24841       // Since all browsers set the input to a valid value, we don't need to check validity
24842       function noopMaxValidator() { return true; } :
24843       // non-support browsers validate the max val
24844       function maxValidator(modelValue, viewValue) {
24845         return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal;
24846       };
24847
24848     setInitialValueAndObserver('max', maxChange);
24849   }
24850
24851   if (hasStepAttr) {
24852     ctrl.$validators.step = supportsRange ?
24853       function nativeStepValidator() {
24854         // Currently, only FF implements the spec on step change correctly (i.e. adjusting the
24855         // input element value to a valid value). It's possible that other browsers set the stepMismatch
24856         // validity error instead, so we can at least report an error in that case.
24857         return !validity.stepMismatch;
24858       } :
24859       // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would
24860       function stepValidator(modelValue, viewValue) {
24861         return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
24862                isValidForStep(viewValue, minVal || 0, stepVal);
24863       };
24864
24865     setInitialValueAndObserver('step', stepChange);
24866   }
24867
24868   function setInitialValueAndObserver(htmlAttrName, changeFn) {
24869     // interpolated attributes set the attribute value only after a digest, but we need the
24870     // attribute value when the input is first rendered, so that the browser can adjust the
24871     // input value based on the min/max value
24872     element.attr(htmlAttrName, attr[htmlAttrName]);
24873     attr.$observe(htmlAttrName, changeFn);
24874   }
24875
24876   function minChange(val) {
24877     minVal = parseNumberAttrVal(val);
24878     // ignore changes before model is initialized
24879     if (isNumberNaN(ctrl.$modelValue)) {
24880       return;
24881     }
24882
24883     if (supportsRange) {
24884       var elVal = element.val();
24885       // IE11 doesn't set the el val correctly if the minVal is greater than the element value
24886       if (minVal > elVal) {
24887         elVal = minVal;
24888         element.val(elVal);
24889       }
24890       ctrl.$setViewValue(elVal);
24891     } else {
24892       // TODO(matsko): implement validateLater to reduce number of validations
24893       ctrl.$validate();
24894     }
24895   }
24896
24897   function maxChange(val) {
24898     maxVal = parseNumberAttrVal(val);
24899     // ignore changes before model is initialized
24900     if (isNumberNaN(ctrl.$modelValue)) {
24901       return;
24902     }
24903
24904     if (supportsRange) {
24905       var elVal = element.val();
24906       // IE11 doesn't set the el val correctly if the maxVal is less than the element value
24907       if (maxVal < elVal) {
24908         element.val(maxVal);
24909         // IE11 and Chrome don't set the value to the minVal when max < min
24910         elVal = maxVal < minVal ? minVal : maxVal;
24911       }
24912       ctrl.$setViewValue(elVal);
24913     } else {
24914       // TODO(matsko): implement validateLater to reduce number of validations
24915       ctrl.$validate();
24916     }
24917   }
24918
24919   function stepChange(val) {
24920     stepVal = parseNumberAttrVal(val);
24921     // ignore changes before model is initialized
24922     if (isNumberNaN(ctrl.$modelValue)) {
24923       return;
24924     }
24925
24926     // Some browsers don't adjust the input value correctly, but set the stepMismatch error
24927     if (supportsRange && ctrl.$viewValue !== element.val()) {
24928       ctrl.$setViewValue(element.val());
24929     } else {
24930       // TODO(matsko): implement validateLater to reduce number of validations
24931       ctrl.$validate();
24932     }
24933   }
24934 }
24935
24936 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24937   // Note: no badInputChecker here by purpose as `url` is only a validation
24938   // in browsers, i.e. we can always read out input.value even if it is not valid!
24939   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24940   stringBasedInputType(ctrl);
24941
24942   ctrl.$$parserName = 'url';
24943   ctrl.$validators.url = function(modelValue, viewValue) {
24944     var value = modelValue || viewValue;
24945     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
24946   };
24947 }
24948
24949 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
24950   // Note: no badInputChecker here by purpose as `url` is only a validation
24951   // in browsers, i.e. we can always read out input.value even if it is not valid!
24952   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
24953   stringBasedInputType(ctrl);
24954
24955   ctrl.$$parserName = 'email';
24956   ctrl.$validators.email = function(modelValue, viewValue) {
24957     var value = modelValue || viewValue;
24958     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
24959   };
24960 }
24961
24962 function radioInputType(scope, element, attr, ctrl) {
24963   // make the name unique, if not defined
24964   if (isUndefined(attr.name)) {
24965     element.attr('name', nextUid());
24966   }
24967
24968   var listener = function(ev) {
24969     if (element[0].checked) {
24970       ctrl.$setViewValue(attr.value, ev && ev.type);
24971     }
24972   };
24973
24974   element.on('click', listener);
24975
24976   ctrl.$render = function() {
24977     var value = attr.value;
24978     // We generally use strict comparison. This is behavior we cannot change without a BC.
24979     // eslint-disable-next-line eqeqeq
24980     element[0].checked = (value == ctrl.$viewValue);
24981   };
24982
24983   attr.$observe('value', ctrl.$render);
24984 }
24985
24986 function parseConstantExpr($parse, context, name, expression, fallback) {
24987   var parseFn;
24988   if (isDefined(expression)) {
24989     parseFn = $parse(expression);
24990     if (!parseFn.constant) {
24991       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
24992                                    '`{1}`.', name, expression);
24993     }
24994     return parseFn(context);
24995   }
24996   return fallback;
24997 }
24998
24999 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
25000   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
25001   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
25002
25003   var listener = function(ev) {
25004     ctrl.$setViewValue(element[0].checked, ev && ev.type);
25005   };
25006
25007   element.on('click', listener);
25008
25009   ctrl.$render = function() {
25010     element[0].checked = ctrl.$viewValue;
25011   };
25012
25013   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
25014   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
25015   // it to a boolean.
25016   ctrl.$isEmpty = function(value) {
25017     return value === false;
25018   };
25019
25020   ctrl.$formatters.push(function(value) {
25021     return equals(value, trueValue);
25022   });
25023
25024   ctrl.$parsers.push(function(value) {
25025     return value ? trueValue : falseValue;
25026   });
25027 }
25028
25029
25030 /**
25031  * @ngdoc directive
25032  * @name textarea
25033  * @restrict E
25034  *
25035  * @description
25036  * HTML textarea element control with angular data-binding. The data-binding and validation
25037  * properties of this element are exactly the same as those of the
25038  * {@link ng.directive:input input element}.
25039  *
25040  * @param {string} ngModel Assignable angular expression to data-bind to.
25041  * @param {string=} name Property name of the form under which the control is published.
25042  * @param {string=} required Sets `required` validation error key if the value is not entered.
25043  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25044  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25045  *    `required` when you want to data-bind to the `required` attribute.
25046  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
25047  *    minlength.
25048  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
25049  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
25050  *    length.
25051  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
25052  *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
25053  *    If the expression evaluates to a RegExp object, then this is used directly.
25054  *    If the expression evaluates to a string, then it will be converted to a RegExp
25055  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
25056  *    `new RegExp('^abc$')`.<br />
25057  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
25058  *    start at the index of the last search's match, thus not taking the whole input value into
25059  *    account.
25060  * @param {string=} ngChange Angular expression to be executed when input changes due to user
25061  *    interaction with the input element.
25062  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
25063  *
25064  * @knownIssue
25065  *
25066  * When specifying the `placeholder` attribute of `<textarea>`, Internet Explorer will temporarily
25067  * insert the placeholder value as the textarea's content. If the placeholder value contains
25068  * interpolation (`{{ ... }}`), an error will be logged in the console when Angular tries to update
25069  * the value of the by-then-removed text node. This doesn't affect the functionality of the
25070  * textarea, but can be undesirable.
25071  *
25072  * You can work around this Internet Explorer issue by using `ng-attr-placeholder` instead of
25073  * `placeholder` on textareas, whenever you need interpolation in the placeholder value. You can
25074  * find more details on `ngAttr` in the
25075  * [Interpolation](guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes) section of the
25076  * Developer Guide.
25077  */
25078
25079
25080 /**
25081  * @ngdoc directive
25082  * @name input
25083  * @restrict E
25084  *
25085  * @description
25086  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
25087  * input state control, and validation.
25088  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
25089  *
25090  * <div class="alert alert-warning">
25091  * **Note:** Not every feature offered is available for all input types.
25092  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
25093  * </div>
25094  *
25095  * @param {string} ngModel Assignable angular expression to data-bind to.
25096  * @param {string=} name Property name of the form under which the control is published.
25097  * @param {string=} required Sets `required` validation error key if the value is not entered.
25098  * @param {boolean=} ngRequired Sets `required` attribute if set to true
25099  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
25100  *    minlength.
25101  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
25102  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
25103  *    length.
25104  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
25105  *    value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
25106  *    If the expression evaluates to a RegExp object, then this is used directly.
25107  *    If the expression evaluates to a string, then it will be converted to a RegExp
25108  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
25109  *    `new RegExp('^abc$')`.<br />
25110  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
25111  *    start at the index of the last search's match, thus not taking the whole input value into
25112  *    account.
25113  * @param {string=} ngChange Angular expression to be executed when input changes due to user
25114  *    interaction with the input element.
25115  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
25116  *    This parameter is ignored for input[type=password] controls, which will never trim the
25117  *    input.
25118  *
25119  * @example
25120     <example name="input-directive" module="inputExample">
25121       <file name="index.html">
25122        <script>
25123           angular.module('inputExample', [])
25124             .controller('ExampleController', ['$scope', function($scope) {
25125               $scope.user = {name: 'guest', last: 'visitor'};
25126             }]);
25127        </script>
25128        <div ng-controller="ExampleController">
25129          <form name="myForm">
25130            <label>
25131               User name:
25132               <input type="text" name="userName" ng-model="user.name" required>
25133            </label>
25134            <div role="alert">
25135              <span class="error" ng-show="myForm.userName.$error.required">
25136               Required!</span>
25137            </div>
25138            <label>
25139               Last name:
25140               <input type="text" name="lastName" ng-model="user.last"
25141               ng-minlength="3" ng-maxlength="10">
25142            </label>
25143            <div role="alert">
25144              <span class="error" ng-show="myForm.lastName.$error.minlength">
25145                Too short!</span>
25146              <span class="error" ng-show="myForm.lastName.$error.maxlength">
25147                Too long!</span>
25148            </div>
25149          </form>
25150          <hr>
25151          <tt>user = {{user}}</tt><br/>
25152          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
25153          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
25154          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
25155          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
25156          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
25157          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
25158          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
25159          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
25160        </div>
25161       </file>
25162       <file name="protractor.js" type="protractor">
25163         var user = element(by.exactBinding('user'));
25164         var userNameValid = element(by.binding('myForm.userName.$valid'));
25165         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
25166         var lastNameError = element(by.binding('myForm.lastName.$error'));
25167         var formValid = element(by.binding('myForm.$valid'));
25168         var userNameInput = element(by.model('user.name'));
25169         var userLastInput = element(by.model('user.last'));
25170
25171         it('should initialize to model', function() {
25172           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
25173           expect(userNameValid.getText()).toContain('true');
25174           expect(formValid.getText()).toContain('true');
25175         });
25176
25177         it('should be invalid if empty when required', function() {
25178           userNameInput.clear();
25179           userNameInput.sendKeys('');
25180
25181           expect(user.getText()).toContain('{"last":"visitor"}');
25182           expect(userNameValid.getText()).toContain('false');
25183           expect(formValid.getText()).toContain('false');
25184         });
25185
25186         it('should be valid if empty when min length is set', function() {
25187           userLastInput.clear();
25188           userLastInput.sendKeys('');
25189
25190           expect(user.getText()).toContain('{"name":"guest","last":""}');
25191           expect(lastNameValid.getText()).toContain('true');
25192           expect(formValid.getText()).toContain('true');
25193         });
25194
25195         it('should be invalid if less than required min length', function() {
25196           userLastInput.clear();
25197           userLastInput.sendKeys('xx');
25198
25199           expect(user.getText()).toContain('{"name":"guest"}');
25200           expect(lastNameValid.getText()).toContain('false');
25201           expect(lastNameError.getText()).toContain('minlength');
25202           expect(formValid.getText()).toContain('false');
25203         });
25204
25205         it('should be invalid if longer than max length', function() {
25206           userLastInput.clear();
25207           userLastInput.sendKeys('some ridiculously long name');
25208
25209           expect(user.getText()).toContain('{"name":"guest"}');
25210           expect(lastNameValid.getText()).toContain('false');
25211           expect(lastNameError.getText()).toContain('maxlength');
25212           expect(formValid.getText()).toContain('false');
25213         });
25214       </file>
25215     </example>
25216  */
25217 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
25218     function($browser, $sniffer, $filter, $parse) {
25219   return {
25220     restrict: 'E',
25221     require: ['?ngModel'],
25222     link: {
25223       pre: function(scope, element, attr, ctrls) {
25224         if (ctrls[0]) {
25225           var type = lowercase(attr.type);
25226           if ((type === 'range') && !attr.hasOwnProperty('ngInputRange')) {
25227             type = 'text';
25228           }
25229           (inputType[type] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
25230                                                               $browser, $filter, $parse);
25231         }
25232       }
25233     }
25234   };
25235 }];
25236
25237
25238
25239 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
25240 /**
25241  * @ngdoc directive
25242  * @name ngValue
25243  *
25244  * @description
25245  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
25246  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
25247  * the bound value.
25248  *
25249  * `ngValue` is useful when dynamically generating lists of radio buttons using
25250  * {@link ngRepeat `ngRepeat`}, as shown below.
25251  *
25252  * Likewise, `ngValue` can be used to generate `<option>` elements for
25253  * the {@link select `select`} element. In that case however, only strings are supported
25254  * for the `value `attribute, so the resulting `ngModel` will always be a string.
25255  * Support for `select` models with non-string values is available via `ngOptions`.
25256  *
25257  * @element input
25258  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
25259  *   of the `input` element
25260  *
25261  * @example
25262     <example name="ngValue-directive" module="valueExample">
25263       <file name="index.html">
25264        <script>
25265           angular.module('valueExample', [])
25266             .controller('ExampleController', ['$scope', function($scope) {
25267               $scope.names = ['pizza', 'unicorns', 'robots'];
25268               $scope.my = { favorite: 'unicorns' };
25269             }]);
25270        </script>
25271         <form ng-controller="ExampleController">
25272           <h2>Which is your favorite?</h2>
25273             <label ng-repeat="name in names" for="{{name}}">
25274               {{name}}
25275               <input type="radio"
25276                      ng-model="my.favorite"
25277                      ng-value="name"
25278                      id="{{name}}"
25279                      name="favorite">
25280             </label>
25281           <div>You chose {{my.favorite}}</div>
25282         </form>
25283       </file>
25284       <file name="protractor.js" type="protractor">
25285         var favorite = element(by.binding('my.favorite'));
25286
25287         it('should initialize to model', function() {
25288           expect(favorite.getText()).toContain('unicorns');
25289         });
25290         it('should bind the values to the inputs', function() {
25291           element.all(by.model('my.favorite')).get(0).click();
25292           expect(favorite.getText()).toContain('pizza');
25293         });
25294       </file>
25295     </example>
25296  */
25297 var ngValueDirective = function() {
25298   return {
25299     restrict: 'A',
25300     priority: 100,
25301     compile: function(tpl, tplAttr) {
25302       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
25303         return function ngValueConstantLink(scope, elm, attr) {
25304           attr.$set('value', scope.$eval(attr.ngValue));
25305         };
25306       } else {
25307         return function ngValueLink(scope, elm, attr) {
25308           scope.$watch(attr.ngValue, function valueWatchAction(value) {
25309             attr.$set('value', value);
25310           });
25311         };
25312       }
25313     }
25314   };
25315 };
25316
25317 /**
25318  * @ngdoc directive
25319  * @name ngBind
25320  * @restrict AC
25321  *
25322  * @description
25323  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
25324  * with the value of a given expression, and to update the text content when the value of that
25325  * expression changes.
25326  *
25327  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
25328  * `{{ expression }}` which is similar but less verbose.
25329  *
25330  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
25331  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
25332  * element attribute, it makes the bindings invisible to the user while the page is loading.
25333  *
25334  * An alternative solution to this problem would be using the
25335  * {@link ng.directive:ngCloak ngCloak} directive.
25336  *
25337  *
25338  * @element ANY
25339  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
25340  *
25341  * @example
25342  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
25343    <example module="bindExample" name="ng-bind">
25344      <file name="index.html">
25345        <script>
25346          angular.module('bindExample', [])
25347            .controller('ExampleController', ['$scope', function($scope) {
25348              $scope.name = 'Whirled';
25349            }]);
25350        </script>
25351        <div ng-controller="ExampleController">
25352          <label>Enter name: <input type="text" ng-model="name"></label><br>
25353          Hello <span ng-bind="name"></span>!
25354        </div>
25355      </file>
25356      <file name="protractor.js" type="protractor">
25357        it('should check ng-bind', function() {
25358          var nameInput = element(by.model('name'));
25359
25360          expect(element(by.binding('name')).getText()).toBe('Whirled');
25361          nameInput.clear();
25362          nameInput.sendKeys('world');
25363          expect(element(by.binding('name')).getText()).toBe('world');
25364        });
25365      </file>
25366    </example>
25367  */
25368 var ngBindDirective = ['$compile', function($compile) {
25369   return {
25370     restrict: 'AC',
25371     compile: function ngBindCompile(templateElement) {
25372       $compile.$$addBindingClass(templateElement);
25373       return function ngBindLink(scope, element, attr) {
25374         $compile.$$addBindingInfo(element, attr.ngBind);
25375         element = element[0];
25376         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
25377           element.textContent = isUndefined(value) ? '' : value;
25378         });
25379       };
25380     }
25381   };
25382 }];
25383
25384
25385 /**
25386  * @ngdoc directive
25387  * @name ngBindTemplate
25388  *
25389  * @description
25390  * The `ngBindTemplate` directive specifies that the element
25391  * text content should be replaced with the interpolation of the template
25392  * in the `ngBindTemplate` attribute.
25393  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
25394  * expressions. This directive is needed since some HTML elements
25395  * (such as TITLE and OPTION) cannot contain SPAN elements.
25396  *
25397  * @element ANY
25398  * @param {string} ngBindTemplate template of form
25399  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
25400  *
25401  * @example
25402  * Try it here: enter text in text box and watch the greeting change.
25403    <example module="bindExample" name="ng-bind-template">
25404      <file name="index.html">
25405        <script>
25406          angular.module('bindExample', [])
25407            .controller('ExampleController', ['$scope', function($scope) {
25408              $scope.salutation = 'Hello';
25409              $scope.name = 'World';
25410            }]);
25411        </script>
25412        <div ng-controller="ExampleController">
25413         <label>Salutation: <input type="text" ng-model="salutation"></label><br>
25414         <label>Name: <input type="text" ng-model="name"></label><br>
25415         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
25416        </div>
25417      </file>
25418      <file name="protractor.js" type="protractor">
25419        it('should check ng-bind', function() {
25420          var salutationElem = element(by.binding('salutation'));
25421          var salutationInput = element(by.model('salutation'));
25422          var nameInput = element(by.model('name'));
25423
25424          expect(salutationElem.getText()).toBe('Hello World!');
25425
25426          salutationInput.clear();
25427          salutationInput.sendKeys('Greetings');
25428          nameInput.clear();
25429          nameInput.sendKeys('user');
25430
25431          expect(salutationElem.getText()).toBe('Greetings user!');
25432        });
25433      </file>
25434    </example>
25435  */
25436 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
25437   return {
25438     compile: function ngBindTemplateCompile(templateElement) {
25439       $compile.$$addBindingClass(templateElement);
25440       return function ngBindTemplateLink(scope, element, attr) {
25441         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
25442         $compile.$$addBindingInfo(element, interpolateFn.expressions);
25443         element = element[0];
25444         attr.$observe('ngBindTemplate', function(value) {
25445           element.textContent = isUndefined(value) ? '' : value;
25446         });
25447       };
25448     }
25449   };
25450 }];
25451
25452
25453 /**
25454  * @ngdoc directive
25455  * @name ngBindHtml
25456  *
25457  * @description
25458  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
25459  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
25460  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
25461  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
25462  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
25463  *
25464  * You may also bypass sanitization for values you know are safe. To do so, bind to
25465  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
25466  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
25467  *
25468  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
25469  * will have an exception (instead of an exploit.)
25470  *
25471  * @element ANY
25472  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
25473  *
25474  * @example
25475
25476    <example module="bindHtmlExample" deps="angular-sanitize.js" name="ng-bind-html">
25477      <file name="index.html">
25478        <div ng-controller="ExampleController">
25479         <p ng-bind-html="myHTML"></p>
25480        </div>
25481      </file>
25482
25483      <file name="script.js">
25484        angular.module('bindHtmlExample', ['ngSanitize'])
25485          .controller('ExampleController', ['$scope', function($scope) {
25486            $scope.myHTML =
25487               'I am an <code>HTML</code>string with ' +
25488               '<a href="#">links!</a> and other <em>stuff</em>';
25489          }]);
25490      </file>
25491
25492      <file name="protractor.js" type="protractor">
25493        it('should check ng-bind-html', function() {
25494          expect(element(by.binding('myHTML')).getText()).toBe(
25495              'I am an HTMLstring with links! and other stuff');
25496        });
25497      </file>
25498    </example>
25499  */
25500 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
25501   return {
25502     restrict: 'A',
25503     compile: function ngBindHtmlCompile(tElement, tAttrs) {
25504       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
25505       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function sceValueOf(val) {
25506         // Unwrap the value to compare the actual inner safe value, not the wrapper object.
25507         return $sce.valueOf(val);
25508       });
25509       $compile.$$addBindingClass(tElement);
25510
25511       return function ngBindHtmlLink(scope, element, attr) {
25512         $compile.$$addBindingInfo(element, attr.ngBindHtml);
25513
25514         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
25515           // The watched value is the unwrapped value. To avoid re-escaping, use the direct getter.
25516           var value = ngBindHtmlGetter(scope);
25517           element.html($sce.getTrustedHtml(value) || '');
25518         });
25519       };
25520     }
25521   };
25522 }];
25523
25524 /**
25525  * @ngdoc directive
25526  * @name ngChange
25527  *
25528  * @description
25529  * Evaluate the given expression when the user changes the input.
25530  * The expression is evaluated immediately, unlike the JavaScript onchange event
25531  * which only triggers at the end of a change (usually, when the user leaves the
25532  * form element or presses the return key).
25533  *
25534  * The `ngChange` expression is only evaluated when a change in the input value causes
25535  * a new value to be committed to the model.
25536  *
25537  * It will not be evaluated:
25538  * * if the value returned from the `$parsers` transformation pipeline has not changed
25539  * * if the input has continued to be invalid since the model will stay `null`
25540  * * if the model is changed programmatically and not by a change to the input value
25541  *
25542  *
25543  * Note, this directive requires `ngModel` to be present.
25544  *
25545  * @element input
25546  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
25547  * in input value.
25548  *
25549  * @example
25550  * <example name="ngChange-directive" module="changeExample">
25551  *   <file name="index.html">
25552  *     <script>
25553  *       angular.module('changeExample', [])
25554  *         .controller('ExampleController', ['$scope', function($scope) {
25555  *           $scope.counter = 0;
25556  *           $scope.change = function() {
25557  *             $scope.counter++;
25558  *           };
25559  *         }]);
25560  *     </script>
25561  *     <div ng-controller="ExampleController">
25562  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
25563  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
25564  *       <label for="ng-change-example2">Confirmed</label><br />
25565  *       <tt>debug = {{confirmed}}</tt><br/>
25566  *       <tt>counter = {{counter}}</tt><br/>
25567  *     </div>
25568  *   </file>
25569  *   <file name="protractor.js" type="protractor">
25570  *     var counter = element(by.binding('counter'));
25571  *     var debug = element(by.binding('confirmed'));
25572  *
25573  *     it('should evaluate the expression if changing from view', function() {
25574  *       expect(counter.getText()).toContain('0');
25575  *
25576  *       element(by.id('ng-change-example1')).click();
25577  *
25578  *       expect(counter.getText()).toContain('1');
25579  *       expect(debug.getText()).toContain('true');
25580  *     });
25581  *
25582  *     it('should not evaluate the expression if changing from model', function() {
25583  *       element(by.id('ng-change-example2')).click();
25584
25585  *       expect(counter.getText()).toContain('0');
25586  *       expect(debug.getText()).toContain('true');
25587  *     });
25588  *   </file>
25589  * </example>
25590  */
25591 var ngChangeDirective = valueFn({
25592   restrict: 'A',
25593   require: 'ngModel',
25594   link: function(scope, element, attr, ctrl) {
25595     ctrl.$viewChangeListeners.push(function() {
25596       scope.$eval(attr.ngChange);
25597     });
25598   }
25599 });
25600
25601 /* exported
25602   ngClassDirective,
25603   ngClassEvenDirective,
25604   ngClassOddDirective
25605 */
25606
25607 function classDirective(name, selector) {
25608   name = 'ngClass' + name;
25609   return ['$animate', function($animate) {
25610     return {
25611       restrict: 'AC',
25612       link: function(scope, element, attr) {
25613         var oldVal;
25614
25615         attr.$observe('class', function(value) {
25616           ngClassWatchAction(scope.$eval(attr[name]));
25617         });
25618
25619
25620         if (name !== 'ngClass') {
25621           scope.$watch('$index', function($index, old$index) {
25622             /* eslint-disable no-bitwise */
25623             var mod = $index & 1;
25624             if (mod !== (old$index & 1)) {
25625               var classes = arrayClasses(oldVal);
25626               if (mod === selector) {
25627                 addClasses(classes);
25628               } else {
25629                 removeClasses(classes);
25630               }
25631             }
25632             /* eslint-enable */
25633           });
25634         }
25635
25636         scope.$watch(attr[name], ngClassWatchAction, true);
25637
25638         function addClasses(classes) {
25639           var newClasses = digestClassCounts(classes, 1);
25640           attr.$addClass(newClasses);
25641         }
25642
25643         function removeClasses(classes) {
25644           var newClasses = digestClassCounts(classes, -1);
25645           attr.$removeClass(newClasses);
25646         }
25647
25648         function digestClassCounts(classes, count) {
25649           // Use createMap() to prevent class assumptions involving property
25650           // names in Object.prototype
25651           var classCounts = element.data('$classCounts') || createMap();
25652           var classesToUpdate = [];
25653           forEach(classes, function(className) {
25654             if (count > 0 || classCounts[className]) {
25655               classCounts[className] = (classCounts[className] || 0) + count;
25656               if (classCounts[className] === +(count > 0)) {
25657                 classesToUpdate.push(className);
25658               }
25659             }
25660           });
25661           element.data('$classCounts', classCounts);
25662           return classesToUpdate.join(' ');
25663         }
25664
25665         function updateClasses(oldClasses, newClasses) {
25666           var toAdd = arrayDifference(newClasses, oldClasses);
25667           var toRemove = arrayDifference(oldClasses, newClasses);
25668           toAdd = digestClassCounts(toAdd, 1);
25669           toRemove = digestClassCounts(toRemove, -1);
25670           if (toAdd && toAdd.length) {
25671             $animate.addClass(element, toAdd);
25672           }
25673           if (toRemove && toRemove.length) {
25674             $animate.removeClass(element, toRemove);
25675           }
25676         }
25677
25678         function ngClassWatchAction(newVal) {
25679           // eslint-disable-next-line no-bitwise
25680           if (selector === true || (scope.$index & 1) === selector) {
25681             var newClasses = arrayClasses(newVal || []);
25682             if (!oldVal) {
25683               addClasses(newClasses);
25684             } else if (!equals(newVal,oldVal)) {
25685               var oldClasses = arrayClasses(oldVal);
25686               updateClasses(oldClasses, newClasses);
25687             }
25688           }
25689           if (isArray(newVal)) {
25690             oldVal = newVal.map(function(v) { return shallowCopy(v); });
25691           } else {
25692             oldVal = shallowCopy(newVal);
25693           }
25694         }
25695       }
25696     };
25697
25698     function arrayDifference(tokens1, tokens2) {
25699       var values = [];
25700
25701       outer:
25702       for (var i = 0; i < tokens1.length; i++) {
25703         var token = tokens1[i];
25704         for (var j = 0; j < tokens2.length; j++) {
25705           if (token === tokens2[j]) continue outer;
25706         }
25707         values.push(token);
25708       }
25709       return values;
25710     }
25711
25712     function arrayClasses(classVal) {
25713       var classes = [];
25714       if (isArray(classVal)) {
25715         forEach(classVal, function(v) {
25716           classes = classes.concat(arrayClasses(v));
25717         });
25718         return classes;
25719       } else if (isString(classVal)) {
25720         return classVal.split(' ');
25721       } else if (isObject(classVal)) {
25722         forEach(classVal, function(v, k) {
25723           if (v) {
25724             classes = classes.concat(k.split(' '));
25725           }
25726         });
25727         return classes;
25728       }
25729       return classVal;
25730     }
25731   }];
25732 }
25733
25734 /**
25735  * @ngdoc directive
25736  * @name ngClass
25737  * @restrict AC
25738  *
25739  * @description
25740  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
25741  * an expression that represents all classes to be added.
25742  *
25743  * The directive operates in three different ways, depending on which of three types the expression
25744  * evaluates to:
25745  *
25746  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
25747  * names.
25748  *
25749  * 2. If the expression evaluates to an object, then for each key-value pair of the
25750  * object with a truthy value the corresponding key is used as a class name.
25751  *
25752  * 3. If the expression evaluates to an array, each element of the array should either be a string as in
25753  * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
25754  * to give you more control over what CSS classes appear. See the code below for an example of this.
25755  *
25756  *
25757  * The directive won't add duplicate classes if a particular class was already set.
25758  *
25759  * When the expression changes, the previously added classes are removed and only then are the
25760  * new classes added.
25761  *
25762  * @knownIssue
25763  * You should not use {@link guide/interpolation interpolation} in the value of the `class`
25764  * attribute, when using the `ngClass` directive on the same element.
25765  * See {@link guide/interpolation#known-issues here} for more info.
25766  *
25767  * @animations
25768  * | Animation                        | Occurs                              |
25769  * |----------------------------------|-------------------------------------|
25770  * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
25771  * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
25772  *
25773  * @element ANY
25774  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
25775  *   of the evaluation can be a string representing space delimited class
25776  *   names, an array, or a map of class names to boolean values. In the case of a map, the
25777  *   names of the properties whose values are truthy will be added as css classes to the
25778  *   element.
25779  *
25780  * @example Example that demonstrates basic bindings via ngClass directive.
25781    <example name="ng-class">
25782      <file name="index.html">
25783        <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
25784        <label>
25785           <input type="checkbox" ng-model="deleted">
25786           deleted (apply "strike" class)
25787        </label><br>
25788        <label>
25789           <input type="checkbox" ng-model="important">
25790           important (apply "bold" class)
25791        </label><br>
25792        <label>
25793           <input type="checkbox" ng-model="error">
25794           error (apply "has-error" class)
25795        </label>
25796        <hr>
25797        <p ng-class="style">Using String Syntax</p>
25798        <input type="text" ng-model="style"
25799               placeholder="Type: bold strike red" aria-label="Type: bold strike red">
25800        <hr>
25801        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
25802        <input ng-model="style1"
25803               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
25804        <input ng-model="style2"
25805               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
25806        <input ng-model="style3"
25807               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
25808        <hr>
25809        <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
25810        <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
25811        <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
25812      </file>
25813      <file name="style.css">
25814        .strike {
25815            text-decoration: line-through;
25816        }
25817        .bold {
25818            font-weight: bold;
25819        }
25820        .red {
25821            color: red;
25822        }
25823        .has-error {
25824            color: red;
25825            background-color: yellow;
25826        }
25827        .orange {
25828            color: orange;
25829        }
25830      </file>
25831      <file name="protractor.js" type="protractor">
25832        var ps = element.all(by.css('p'));
25833
25834        it('should let you toggle the class', function() {
25835
25836          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
25837          expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
25838
25839          element(by.model('important')).click();
25840          expect(ps.first().getAttribute('class')).toMatch(/bold/);
25841
25842          element(by.model('error')).click();
25843          expect(ps.first().getAttribute('class')).toMatch(/has-error/);
25844        });
25845
25846        it('should let you toggle string example', function() {
25847          expect(ps.get(1).getAttribute('class')).toBe('');
25848          element(by.model('style')).clear();
25849          element(by.model('style')).sendKeys('red');
25850          expect(ps.get(1).getAttribute('class')).toBe('red');
25851        });
25852
25853        it('array example should have 3 classes', function() {
25854          expect(ps.get(2).getAttribute('class')).toBe('');
25855          element(by.model('style1')).sendKeys('bold');
25856          element(by.model('style2')).sendKeys('strike');
25857          element(by.model('style3')).sendKeys('red');
25858          expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
25859        });
25860
25861        it('array with map example should have 2 classes', function() {
25862          expect(ps.last().getAttribute('class')).toBe('');
25863          element(by.model('style4')).sendKeys('bold');
25864          element(by.model('warning')).click();
25865          expect(ps.last().getAttribute('class')).toBe('bold orange');
25866        });
25867      </file>
25868    </example>
25869
25870    ## Animations
25871
25872    The example below demonstrates how to perform animations using ngClass.
25873
25874    <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-class">
25875      <file name="index.html">
25876       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
25877       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
25878       <br>
25879       <span class="base-class" ng-class="myVar">Sample Text</span>
25880      </file>
25881      <file name="style.css">
25882        .base-class {
25883          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25884        }
25885
25886        .base-class.my-class {
25887          color: red;
25888          font-size:3em;
25889        }
25890      </file>
25891      <file name="protractor.js" type="protractor">
25892        it('should check ng-class', function() {
25893          expect(element(by.css('.base-class')).getAttribute('class')).not.
25894            toMatch(/my-class/);
25895
25896          element(by.id('setbtn')).click();
25897
25898          expect(element(by.css('.base-class')).getAttribute('class')).
25899            toMatch(/my-class/);
25900
25901          element(by.id('clearbtn')).click();
25902
25903          expect(element(by.css('.base-class')).getAttribute('class')).not.
25904            toMatch(/my-class/);
25905        });
25906      </file>
25907    </example>
25908
25909
25910    ## ngClass and pre-existing CSS3 Transitions/Animations
25911    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
25912    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
25913    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
25914    to view the step by step details of {@link $animate#addClass $animate.addClass} and
25915    {@link $animate#removeClass $animate.removeClass}.
25916  */
25917 var ngClassDirective = classDirective('', true);
25918
25919 /**
25920  * @ngdoc directive
25921  * @name ngClassOdd
25922  * @restrict AC
25923  *
25924  * @description
25925  * The `ngClassOdd` and `ngClassEven` directives work exactly as
25926  * {@link ng.directive:ngClass ngClass}, except they work in
25927  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
25928  *
25929  * This directive can be applied only within the scope of an
25930  * {@link ng.directive:ngRepeat ngRepeat}.
25931  *
25932  * @element ANY
25933  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
25934  *   of the evaluation can be a string representing space delimited class names or an array.
25935  *
25936  * @example
25937    <example name="ng-class-odd">
25938      <file name="index.html">
25939         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
25940           <li ng-repeat="name in names">
25941            <span ng-class-odd="'odd'" ng-class-even="'even'">
25942              {{name}}
25943            </span>
25944           </li>
25945         </ol>
25946      </file>
25947      <file name="style.css">
25948        .odd {
25949          color: red;
25950        }
25951        .even {
25952          color: blue;
25953        }
25954      </file>
25955      <file name="protractor.js" type="protractor">
25956        it('should check ng-class-odd and ng-class-even', function() {
25957          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
25958            toMatch(/odd/);
25959          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
25960            toMatch(/even/);
25961        });
25962      </file>
25963    </example>
25964  */
25965 var ngClassOddDirective = classDirective('Odd', 0);
25966
25967 /**
25968  * @ngdoc directive
25969  * @name ngClassEven
25970  * @restrict AC
25971  *
25972  * @description
25973  * The `ngClassOdd` and `ngClassEven` directives work exactly as
25974  * {@link ng.directive:ngClass ngClass}, except they work in
25975  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
25976  *
25977  * This directive can be applied only within the scope of an
25978  * {@link ng.directive:ngRepeat ngRepeat}.
25979  *
25980  * @element ANY
25981  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
25982  *   result of the evaluation can be a string representing space delimited class names or an array.
25983  *
25984  * @example
25985    <example name="ng-class-even">
25986      <file name="index.html">
25987         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
25988           <li ng-repeat="name in names">
25989            <span ng-class-odd="'odd'" ng-class-even="'even'">
25990              {{name}} &nbsp; &nbsp; &nbsp;
25991            </span>
25992           </li>
25993         </ol>
25994      </file>
25995      <file name="style.css">
25996        .odd {
25997          color: red;
25998        }
25999        .even {
26000          color: blue;
26001        }
26002      </file>
26003      <file name="protractor.js" type="protractor">
26004        it('should check ng-class-odd and ng-class-even', function() {
26005          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
26006            toMatch(/odd/);
26007          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
26008            toMatch(/even/);
26009        });
26010      </file>
26011    </example>
26012  */
26013 var ngClassEvenDirective = classDirective('Even', 1);
26014
26015 /**
26016  * @ngdoc directive
26017  * @name ngCloak
26018  * @restrict AC
26019  *
26020  * @description
26021  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
26022  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
26023  * directive to avoid the undesirable flicker effect caused by the html template display.
26024  *
26025  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
26026  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
26027  * of the browser view.
26028  *
26029  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
26030  * `angular.min.js`.
26031  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
26032  *
26033  * ```css
26034  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
26035  *   display: none !important;
26036  * }
26037  * ```
26038  *
26039  * When this css rule is loaded by the browser, all html elements (including their children) that
26040  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
26041  * during the compilation of the template it deletes the `ngCloak` element attribute, making
26042  * the compiled element visible.
26043  *
26044  * For the best result, the `angular.js` script must be loaded in the head section of the html
26045  * document; alternatively, the css rule above must be included in the external stylesheet of the
26046  * application.
26047  *
26048  * @element ANY
26049  *
26050  * @example
26051    <example name="ng-cloak">
26052      <file name="index.html">
26053         <div id="template1" ng-cloak>{{ 'hello' }}</div>
26054         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
26055      </file>
26056      <file name="protractor.js" type="protractor">
26057        it('should remove the template directive and css class', function() {
26058          expect($('#template1').getAttribute('ng-cloak')).
26059            toBeNull();
26060          expect($('#template2').getAttribute('ng-cloak')).
26061            toBeNull();
26062        });
26063      </file>
26064    </example>
26065  *
26066  */
26067 var ngCloakDirective = ngDirective({
26068   compile: function(element, attr) {
26069     attr.$set('ngCloak', undefined);
26070     element.removeClass('ng-cloak');
26071   }
26072 });
26073
26074 /**
26075  * @ngdoc directive
26076  * @name ngController
26077  *
26078  * @description
26079  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
26080  * supports the principles behind the Model-View-Controller design pattern.
26081  *
26082  * MVC components in angular:
26083  *
26084  * * Model â€” Models are the properties of a scope; scopes are attached to the DOM where scope properties
26085  *   are accessed through bindings.
26086  * * View â€” The template (HTML with data bindings) that is rendered into the View.
26087  * * Controller â€” The `ngController` directive specifies a Controller class; the class contains business
26088  *   logic behind the application to decorate the scope with functions and values
26089  *
26090  * Note that you can also attach controllers to the DOM by declaring it in a route definition
26091  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
26092  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
26093  * and executed twice.
26094  *
26095  * @element ANY
26096  * @scope
26097  * @priority 500
26098  * @param {expression} ngController Name of a constructor function registered with the current
26099  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
26100  * that on the current scope evaluates to a constructor function.
26101  *
26102  * The controller instance can be published into a scope property by specifying
26103  * `ng-controller="as propertyName"`.
26104  *
26105  * If the current `$controllerProvider` is configured to use globals (via
26106  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
26107  * also be the name of a globally accessible constructor function (not recommended).
26108  *
26109  * @example
26110  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
26111  * greeting are methods declared on the controller (see source tab). These methods can
26112  * easily be called from the angular markup. Any changes to the data are automatically reflected
26113  * in the View without the need for a manual update.
26114  *
26115  * Two different declaration styles are included below:
26116  *
26117  * * one binds methods and properties directly onto the controller using `this`:
26118  * `ng-controller="SettingsController1 as settings"`
26119  * * one injects `$scope` into the controller:
26120  * `ng-controller="SettingsController2"`
26121  *
26122  * The second option is more common in the Angular community, and is generally used in boilerplates
26123  * and in this guide. However, there are advantages to binding properties directly to the controller
26124  * and avoiding scope.
26125  *
26126  * * Using `controller as` makes it obvious which controller you are accessing in the template when
26127  * multiple controllers apply to an element.
26128  * * If you are writing your controllers as classes you have easier access to the properties and
26129  * methods, which will appear on the scope, from inside the controller code.
26130  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
26131  * inheritance masking primitives.
26132  *
26133  * This example demonstrates the `controller as` syntax.
26134  *
26135  * <example name="ngControllerAs" module="controllerAsExample">
26136  *   <file name="index.html">
26137  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
26138  *      <label>Name: <input type="text" ng-model="settings.name"/></label>
26139  *      <button ng-click="settings.greet()">greet</button><br/>
26140  *      Contact:
26141  *      <ul>
26142  *        <li ng-repeat="contact in settings.contacts">
26143  *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
26144  *             <option>phone</option>
26145  *             <option>email</option>
26146  *          </select>
26147  *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
26148  *          <button ng-click="settings.clearContact(contact)">clear</button>
26149  *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
26150  *        </li>
26151  *        <li><button ng-click="settings.addContact()">add</button></li>
26152  *     </ul>
26153  *    </div>
26154  *   </file>
26155  *   <file name="app.js">
26156  *    angular.module('controllerAsExample', [])
26157  *      .controller('SettingsController1', SettingsController1);
26158  *
26159  *    function SettingsController1() {
26160  *      this.name = 'John Smith';
26161  *      this.contacts = [
26162  *        {type: 'phone', value: '408 555 1212'},
26163  *        {type: 'email', value: 'john.smith@example.org'}
26164  *      ];
26165  *    }
26166  *
26167  *    SettingsController1.prototype.greet = function() {
26168  *      alert(this.name);
26169  *    };
26170  *
26171  *    SettingsController1.prototype.addContact = function() {
26172  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
26173  *    };
26174  *
26175  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
26176  *     var index = this.contacts.indexOf(contactToRemove);
26177  *      this.contacts.splice(index, 1);
26178  *    };
26179  *
26180  *    SettingsController1.prototype.clearContact = function(contact) {
26181  *      contact.type = 'phone';
26182  *      contact.value = '';
26183  *    };
26184  *   </file>
26185  *   <file name="protractor.js" type="protractor">
26186  *     it('should check controller as', function() {
26187  *       var container = element(by.id('ctrl-as-exmpl'));
26188  *         expect(container.element(by.model('settings.name'))
26189  *           .getAttribute('value')).toBe('John Smith');
26190  *
26191  *       var firstRepeat =
26192  *           container.element(by.repeater('contact in settings.contacts').row(0));
26193  *       var secondRepeat =
26194  *           container.element(by.repeater('contact in settings.contacts').row(1));
26195  *
26196  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
26197  *           .toBe('408 555 1212');
26198  *
26199  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
26200  *           .toBe('john.smith@example.org');
26201  *
26202  *       firstRepeat.element(by.buttonText('clear')).click();
26203  *
26204  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
26205  *           .toBe('');
26206  *
26207  *       container.element(by.buttonText('add')).click();
26208  *
26209  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
26210  *           .element(by.model('contact.value'))
26211  *           .getAttribute('value'))
26212  *           .toBe('yourname@example.org');
26213  *     });
26214  *   </file>
26215  * </example>
26216  *
26217  * This example demonstrates the "attach to `$scope`" style of controller.
26218  *
26219  * <example name="ngController" module="controllerExample">
26220  *  <file name="index.html">
26221  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
26222  *     <label>Name: <input type="text" ng-model="name"/></label>
26223  *     <button ng-click="greet()">greet</button><br/>
26224  *     Contact:
26225  *     <ul>
26226  *       <li ng-repeat="contact in contacts">
26227  *         <select ng-model="contact.type" id="select_{{$index}}">
26228  *            <option>phone</option>
26229  *            <option>email</option>
26230  *         </select>
26231  *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
26232  *         <button ng-click="clearContact(contact)">clear</button>
26233  *         <button ng-click="removeContact(contact)">X</button>
26234  *       </li>
26235  *       <li>[ <button ng-click="addContact()">add</button> ]</li>
26236  *    </ul>
26237  *   </div>
26238  *  </file>
26239  *  <file name="app.js">
26240  *   angular.module('controllerExample', [])
26241  *     .controller('SettingsController2', ['$scope', SettingsController2]);
26242  *
26243  *   function SettingsController2($scope) {
26244  *     $scope.name = 'John Smith';
26245  *     $scope.contacts = [
26246  *       {type:'phone', value:'408 555 1212'},
26247  *       {type:'email', value:'john.smith@example.org'}
26248  *     ];
26249  *
26250  *     $scope.greet = function() {
26251  *       alert($scope.name);
26252  *     };
26253  *
26254  *     $scope.addContact = function() {
26255  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
26256  *     };
26257  *
26258  *     $scope.removeContact = function(contactToRemove) {
26259  *       var index = $scope.contacts.indexOf(contactToRemove);
26260  *       $scope.contacts.splice(index, 1);
26261  *     };
26262  *
26263  *     $scope.clearContact = function(contact) {
26264  *       contact.type = 'phone';
26265  *       contact.value = '';
26266  *     };
26267  *   }
26268  *  </file>
26269  *  <file name="protractor.js" type="protractor">
26270  *    it('should check controller', function() {
26271  *      var container = element(by.id('ctrl-exmpl'));
26272  *
26273  *      expect(container.element(by.model('name'))
26274  *          .getAttribute('value')).toBe('John Smith');
26275  *
26276  *      var firstRepeat =
26277  *          container.element(by.repeater('contact in contacts').row(0));
26278  *      var secondRepeat =
26279  *          container.element(by.repeater('contact in contacts').row(1));
26280  *
26281  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
26282  *          .toBe('408 555 1212');
26283  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
26284  *          .toBe('john.smith@example.org');
26285  *
26286  *      firstRepeat.element(by.buttonText('clear')).click();
26287  *
26288  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
26289  *          .toBe('');
26290  *
26291  *      container.element(by.buttonText('add')).click();
26292  *
26293  *      expect(container.element(by.repeater('contact in contacts').row(2))
26294  *          .element(by.model('contact.value'))
26295  *          .getAttribute('value'))
26296  *          .toBe('yourname@example.org');
26297  *    });
26298  *  </file>
26299  *</example>
26300
26301  */
26302 var ngControllerDirective = [function() {
26303   return {
26304     restrict: 'A',
26305     scope: true,
26306     controller: '@',
26307     priority: 500
26308   };
26309 }];
26310
26311 /**
26312  * @ngdoc directive
26313  * @name ngCsp
26314  *
26315  * @restrict A
26316  * @element ANY
26317  * @description
26318  *
26319  * Angular has some features that can conflict with certain restrictions that are applied when using
26320  * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
26321  *
26322  * If you intend to implement CSP with these rules then you must tell Angular not to use these
26323  * features.
26324  *
26325  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
26326  *
26327  *
26328  * The following default rules in CSP affect Angular:
26329  *
26330  * * The use of `eval()`, `Function(string)` and similar functions to dynamically create and execute
26331  * code from strings is forbidden. Angular makes use of this in the {@link $parse} service to
26332  * provide a 30% increase in the speed of evaluating Angular expressions. (This CSP rule can be
26333  * disabled with the CSP keyword `unsafe-eval`, but it is generally not recommended as it would
26334  * weaken the protections offered by CSP.)
26335  *
26336  * * The use of inline resources, such as inline `<script>` and `<style>` elements, are forbidden.
26337  * This prevents apps from injecting custom styles directly into the document. Angular makes use of
26338  * this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}). To make these
26339  * directives work when a CSP rule is blocking inline styles, you must link to the `angular-csp.css`
26340  * in your HTML manually. (This CSP rule can be disabled with the CSP keyword `unsafe-inline`, but
26341  * it is generally not recommended as it would weaken the protections offered by CSP.)
26342  *
26343  * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking dynamic code
26344  * creation from strings (e.g., `unsafe-eval` not specified in CSP header) and automatically
26345  * deactivates this feature in the {@link $parse} service. This autodetection, however, triggers a
26346  * CSP error to be logged in the console:
26347  *
26348  * ```
26349  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
26350  * script in the following Content Security Policy directive: "default-src 'self'". Note that
26351  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
26352  * ```
26353  *
26354  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
26355  * directive on an element of the HTML document that appears before the `<script>` tag that loads
26356  * the `angular.js` file.
26357  *
26358  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
26359  *
26360  * You can specify which of the CSP related Angular features should be deactivated by providing
26361  * a value for the `ng-csp` attribute. The options are as follows:
26362  *
26363  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
26364  *
26365  * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
26366  *
26367  * You can use these values in the following combinations:
26368  *
26369  *
26370  * * No declaration means that Angular will assume that you can do inline styles, but it will do
26371  * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous
26372  * versions of Angular.
26373  *
26374  * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
26375  * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous
26376  * versions of Angular.
26377  *
26378  * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can
26379  * inject inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
26380  *
26381  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
26382  * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
26383  *
26384  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
26385  * styles nor use eval, which is the same as an empty: ng-csp.
26386  * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
26387  *
26388  * @example
26389  * This example shows how to apply the `ngCsp` directive to the `html` tag.
26390    ```html
26391      <!doctype html>
26392      <html ng-app ng-csp>
26393      ...
26394      ...
26395      </html>
26396    ```
26397   * @example
26398       <!-- Note: the `.csp` suffix in the example name triggers CSP mode in our http server! -->
26399       <example name="example.csp" module="cspExample" ng-csp="true">
26400         <file name="index.html">
26401           <div ng-controller="MainController as ctrl">
26402             <div>
26403               <button ng-click="ctrl.inc()" id="inc">Increment</button>
26404               <span id="counter">
26405                 {{ctrl.counter}}
26406               </span>
26407             </div>
26408
26409             <div>
26410               <button ng-click="ctrl.evil()" id="evil">Evil</button>
26411               <span id="evilError">
26412                 {{ctrl.evilError}}
26413               </span>
26414             </div>
26415           </div>
26416         </file>
26417         <file name="script.js">
26418            angular.module('cspExample', [])
26419              .controller('MainController', function MainController() {
26420                 this.counter = 0;
26421                 this.inc = function() {
26422                   this.counter++;
26423                 };
26424                 this.evil = function() {
26425                   try {
26426                     eval('1+2'); // eslint-disable-line no-eval
26427                   } catch (e) {
26428                     this.evilError = e.message;
26429                   }
26430                 };
26431               });
26432         </file>
26433         <file name="protractor.js" type="protractor">
26434           var util, webdriver;
26435
26436           var incBtn = element(by.id('inc'));
26437           var counter = element(by.id('counter'));
26438           var evilBtn = element(by.id('evil'));
26439           var evilError = element(by.id('evilError'));
26440
26441           function getAndClearSevereErrors() {
26442             return browser.manage().logs().get('browser').then(function(browserLog) {
26443               return browserLog.filter(function(logEntry) {
26444                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
26445               });
26446             });
26447           }
26448
26449           function clearErrors() {
26450             getAndClearSevereErrors();
26451           }
26452
26453           function expectNoErrors() {
26454             getAndClearSevereErrors().then(function(filteredLog) {
26455               expect(filteredLog.length).toEqual(0);
26456               if (filteredLog.length) {
26457                 console.log('browser console errors: ' + util.inspect(filteredLog));
26458               }
26459             });
26460           }
26461
26462           function expectError(regex) {
26463             getAndClearSevereErrors().then(function(filteredLog) {
26464               var found = false;
26465               filteredLog.forEach(function(log) {
26466                 if (log.message.match(regex)) {
26467                   found = true;
26468                 }
26469               });
26470               if (!found) {
26471                 throw new Error('expected an error that matches ' + regex);
26472               }
26473             });
26474           }
26475
26476           beforeEach(function() {
26477             util = require('util');
26478             webdriver = require('selenium-webdriver');
26479           });
26480
26481           // For now, we only test on Chrome,
26482           // as Safari does not load the page with Protractor's injected scripts,
26483           // and Firefox webdriver always disables content security policy (#6358)
26484           if (browser.params.browser !== 'chrome') {
26485             return;
26486           }
26487
26488           it('should not report errors when the page is loaded', function() {
26489             // clear errors so we are not dependent on previous tests
26490             clearErrors();
26491             // Need to reload the page as the page is already loaded when
26492             // we come here
26493             browser.driver.getCurrentUrl().then(function(url) {
26494               browser.get(url);
26495             });
26496             expectNoErrors();
26497           });
26498
26499           it('should evaluate expressions', function() {
26500             expect(counter.getText()).toEqual('0');
26501             incBtn.click();
26502             expect(counter.getText()).toEqual('1');
26503             expectNoErrors();
26504           });
26505
26506           it('should throw and report an error when using "eval"', function() {
26507             evilBtn.click();
26508             expect(evilError.getText()).toMatch(/Content Security Policy/);
26509             expectError(/Content Security Policy/);
26510           });
26511         </file>
26512       </example>
26513   */
26514
26515 // `ngCsp` is not implemented as a proper directive any more, because we need it be processed while
26516 // we bootstrap the app (before `$parse` is instantiated). For this reason, we just have the `csp()`
26517 // fn that looks for the `ng-csp` attribute anywhere in the current doc.
26518
26519 /**
26520  * @ngdoc directive
26521  * @name ngClick
26522  *
26523  * @description
26524  * The ngClick directive allows you to specify custom behavior when
26525  * an element is clicked.
26526  *
26527  * @element ANY
26528  * @priority 0
26529  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
26530  * click. ({@link guide/expression#-event- Event object is available as `$event`})
26531  *
26532  * @example
26533    <example name="ng-click">
26534      <file name="index.html">
26535       <button ng-click="count = count + 1" ng-init="count=0">
26536         Increment
26537       </button>
26538       <span>
26539         count: {{count}}
26540       </span>
26541      </file>
26542      <file name="protractor.js" type="protractor">
26543        it('should check ng-click', function() {
26544          expect(element(by.binding('count')).getText()).toMatch('0');
26545          element(by.css('button')).click();
26546          expect(element(by.binding('count')).getText()).toMatch('1');
26547        });
26548      </file>
26549    </example>
26550  */
26551 /*
26552  * A collection of directives that allows creation of custom event handlers that are defined as
26553  * angular expressions and are compiled and executed within the current scope.
26554  */
26555 var ngEventDirectives = {};
26556
26557 // For events that might fire synchronously during DOM manipulation
26558 // we need to execute their event handlers asynchronously using $evalAsync,
26559 // so that they are not executed in an inconsistent state.
26560 var forceAsyncEvents = {
26561   'blur': true,
26562   'focus': true
26563 };
26564 forEach(
26565   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
26566   function(eventName) {
26567     var directiveName = directiveNormalize('ng-' + eventName);
26568     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
26569       return {
26570         restrict: 'A',
26571         compile: function($element, attr) {
26572           // We expose the powerful $event object on the scope that provides access to the Window,
26573           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
26574           // checks at the cost of speed since event handler expressions are not executed as
26575           // frequently as regular change detection.
26576           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
26577           return function ngEventHandler(scope, element) {
26578             element.on(eventName, function(event) {
26579               var callback = function() {
26580                 fn(scope, {$event:event});
26581               };
26582               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
26583                 scope.$evalAsync(callback);
26584               } else {
26585                 scope.$apply(callback);
26586               }
26587             });
26588           };
26589         }
26590       };
26591     }];
26592   }
26593 );
26594
26595 /**
26596  * @ngdoc directive
26597  * @name ngDblclick
26598  *
26599  * @description
26600  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
26601  *
26602  * @element ANY
26603  * @priority 0
26604  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
26605  * a dblclick. (The Event object is available as `$event`)
26606  *
26607  * @example
26608    <example name="ng-dblclick">
26609      <file name="index.html">
26610       <button ng-dblclick="count = count + 1" ng-init="count=0">
26611         Increment (on double click)
26612       </button>
26613       count: {{count}}
26614      </file>
26615    </example>
26616  */
26617
26618
26619 /**
26620  * @ngdoc directive
26621  * @name ngMousedown
26622  *
26623  * @description
26624  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
26625  *
26626  * @element ANY
26627  * @priority 0
26628  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
26629  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
26630  *
26631  * @example
26632    <example name="ng-mousedown">
26633      <file name="index.html">
26634       <button ng-mousedown="count = count + 1" ng-init="count=0">
26635         Increment (on mouse down)
26636       </button>
26637       count: {{count}}
26638      </file>
26639    </example>
26640  */
26641
26642
26643 /**
26644  * @ngdoc directive
26645  * @name ngMouseup
26646  *
26647  * @description
26648  * Specify custom behavior on mouseup event.
26649  *
26650  * @element ANY
26651  * @priority 0
26652  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
26653  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
26654  *
26655  * @example
26656    <example name="ng-mouseup">
26657      <file name="index.html">
26658       <button ng-mouseup="count = count + 1" ng-init="count=0">
26659         Increment (on mouse up)
26660       </button>
26661       count: {{count}}
26662      </file>
26663    </example>
26664  */
26665
26666 /**
26667  * @ngdoc directive
26668  * @name ngMouseover
26669  *
26670  * @description
26671  * Specify custom behavior on mouseover event.
26672  *
26673  * @element ANY
26674  * @priority 0
26675  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
26676  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
26677  *
26678  * @example
26679    <example name="ng-mouseover">
26680      <file name="index.html">
26681       <button ng-mouseover="count = count + 1" ng-init="count=0">
26682         Increment (when mouse is over)
26683       </button>
26684       count: {{count}}
26685      </file>
26686    </example>
26687  */
26688
26689
26690 /**
26691  * @ngdoc directive
26692  * @name ngMouseenter
26693  *
26694  * @description
26695  * Specify custom behavior on mouseenter event.
26696  *
26697  * @element ANY
26698  * @priority 0
26699  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
26700  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
26701  *
26702  * @example
26703    <example name="ng-mouseenter">
26704      <file name="index.html">
26705       <button ng-mouseenter="count = count + 1" ng-init="count=0">
26706         Increment (when mouse enters)
26707       </button>
26708       count: {{count}}
26709      </file>
26710    </example>
26711  */
26712
26713
26714 /**
26715  * @ngdoc directive
26716  * @name ngMouseleave
26717  *
26718  * @description
26719  * Specify custom behavior on mouseleave event.
26720  *
26721  * @element ANY
26722  * @priority 0
26723  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
26724  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
26725  *
26726  * @example
26727    <example name="ng-mouseleave">
26728      <file name="index.html">
26729       <button ng-mouseleave="count = count + 1" ng-init="count=0">
26730         Increment (when mouse leaves)
26731       </button>
26732       count: {{count}}
26733      </file>
26734    </example>
26735  */
26736
26737
26738 /**
26739  * @ngdoc directive
26740  * @name ngMousemove
26741  *
26742  * @description
26743  * Specify custom behavior on mousemove event.
26744  *
26745  * @element ANY
26746  * @priority 0
26747  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
26748  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
26749  *
26750  * @example
26751    <example name="ng-mousemove">
26752      <file name="index.html">
26753       <button ng-mousemove="count = count + 1" ng-init="count=0">
26754         Increment (when mouse moves)
26755       </button>
26756       count: {{count}}
26757      </file>
26758    </example>
26759  */
26760
26761
26762 /**
26763  * @ngdoc directive
26764  * @name ngKeydown
26765  *
26766  * @description
26767  * Specify custom behavior on keydown event.
26768  *
26769  * @element ANY
26770  * @priority 0
26771  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
26772  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
26773  *
26774  * @example
26775    <example name="ng-keydown">
26776      <file name="index.html">
26777       <input ng-keydown="count = count + 1" ng-init="count=0">
26778       key down count: {{count}}
26779      </file>
26780    </example>
26781  */
26782
26783
26784 /**
26785  * @ngdoc directive
26786  * @name ngKeyup
26787  *
26788  * @description
26789  * Specify custom behavior on keyup event.
26790  *
26791  * @element ANY
26792  * @priority 0
26793  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
26794  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
26795  *
26796  * @example
26797    <example name="ng-keyup">
26798      <file name="index.html">
26799        <p>Typing in the input box below updates the key count</p>
26800        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
26801
26802        <p>Typing in the input box below updates the keycode</p>
26803        <input ng-keyup="event=$event">
26804        <p>event keyCode: {{ event.keyCode }}</p>
26805        <p>event altKey: {{ event.altKey }}</p>
26806      </file>
26807    </example>
26808  */
26809
26810
26811 /**
26812  * @ngdoc directive
26813  * @name ngKeypress
26814  *
26815  * @description
26816  * Specify custom behavior on keypress event.
26817  *
26818  * @element ANY
26819  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
26820  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
26821  * and can be interrogated for keyCode, altKey, etc.)
26822  *
26823  * @example
26824    <example name="ng-keypress">
26825      <file name="index.html">
26826       <input ng-keypress="count = count + 1" ng-init="count=0">
26827       key press count: {{count}}
26828      </file>
26829    </example>
26830  */
26831
26832
26833 /**
26834  * @ngdoc directive
26835  * @name ngSubmit
26836  *
26837  * @description
26838  * Enables binding angular expressions to onsubmit events.
26839  *
26840  * Additionally it prevents the default action (which for form means sending the request to the
26841  * server and reloading the current page), but only if the form does not contain `action`,
26842  * `data-action`, or `x-action` attributes.
26843  *
26844  * <div class="alert alert-warning">
26845  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
26846  * `ngSubmit` handlers together. See the
26847  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
26848  * for a detailed discussion of when `ngSubmit` may be triggered.
26849  * </div>
26850  *
26851  * @element form
26852  * @priority 0
26853  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
26854  * ({@link guide/expression#-event- Event object is available as `$event`})
26855  *
26856  * @example
26857    <example module="submitExample" name="ng-submit">
26858      <file name="index.html">
26859       <script>
26860         angular.module('submitExample', [])
26861           .controller('ExampleController', ['$scope', function($scope) {
26862             $scope.list = [];
26863             $scope.text = 'hello';
26864             $scope.submit = function() {
26865               if ($scope.text) {
26866                 $scope.list.push(this.text);
26867                 $scope.text = '';
26868               }
26869             };
26870           }]);
26871       </script>
26872       <form ng-submit="submit()" ng-controller="ExampleController">
26873         Enter text and hit enter:
26874         <input type="text" ng-model="text" name="text" />
26875         <input type="submit" id="submit" value="Submit" />
26876         <pre>list={{list}}</pre>
26877       </form>
26878      </file>
26879      <file name="protractor.js" type="protractor">
26880        it('should check ng-submit', function() {
26881          expect(element(by.binding('list')).getText()).toBe('list=[]');
26882          element(by.css('#submit')).click();
26883          expect(element(by.binding('list')).getText()).toContain('hello');
26884          expect(element(by.model('text')).getAttribute('value')).toBe('');
26885        });
26886        it('should ignore empty strings', function() {
26887          expect(element(by.binding('list')).getText()).toBe('list=[]');
26888          element(by.css('#submit')).click();
26889          element(by.css('#submit')).click();
26890          expect(element(by.binding('list')).getText()).toContain('hello');
26891         });
26892      </file>
26893    </example>
26894  */
26895
26896 /**
26897  * @ngdoc directive
26898  * @name ngFocus
26899  *
26900  * @description
26901  * Specify custom behavior on focus event.
26902  *
26903  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
26904  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
26905  * during an `$apply` to ensure a consistent state.
26906  *
26907  * @element window, input, select, textarea, a
26908  * @priority 0
26909  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
26910  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
26911  *
26912  * @example
26913  * See {@link ng.directive:ngClick ngClick}
26914  */
26915
26916 /**
26917  * @ngdoc directive
26918  * @name ngBlur
26919  *
26920  * @description
26921  * Specify custom behavior on blur event.
26922  *
26923  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
26924  * an element has lost focus.
26925  *
26926  * Note: As the `blur` event is executed synchronously also during DOM manipulations
26927  * (e.g. removing a focussed input),
26928  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
26929  * during an `$apply` to ensure a consistent state.
26930  *
26931  * @element window, input, select, textarea, a
26932  * @priority 0
26933  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
26934  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
26935  *
26936  * @example
26937  * See {@link ng.directive:ngClick ngClick}
26938  */
26939
26940 /**
26941  * @ngdoc directive
26942  * @name ngCopy
26943  *
26944  * @description
26945  * Specify custom behavior on copy event.
26946  *
26947  * @element window, input, select, textarea, a
26948  * @priority 0
26949  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
26950  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
26951  *
26952  * @example
26953    <example name="ng-copy">
26954      <file name="index.html">
26955       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
26956       copied: {{copied}}
26957      </file>
26958    </example>
26959  */
26960
26961 /**
26962  * @ngdoc directive
26963  * @name ngCut
26964  *
26965  * @description
26966  * Specify custom behavior on cut event.
26967  *
26968  * @element window, input, select, textarea, a
26969  * @priority 0
26970  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
26971  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
26972  *
26973  * @example
26974    <example name="ng-cut">
26975      <file name="index.html">
26976       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
26977       cut: {{cut}}
26978      </file>
26979    </example>
26980  */
26981
26982 /**
26983  * @ngdoc directive
26984  * @name ngPaste
26985  *
26986  * @description
26987  * Specify custom behavior on paste event.
26988  *
26989  * @element window, input, select, textarea, a
26990  * @priority 0
26991  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
26992  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
26993  *
26994  * @example
26995    <example name="ng-paste">
26996      <file name="index.html">
26997       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
26998       pasted: {{paste}}
26999      </file>
27000    </example>
27001  */
27002
27003 /**
27004  * @ngdoc directive
27005  * @name ngIf
27006  * @restrict A
27007  * @multiElement
27008  *
27009  * @description
27010  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
27011  * {expression}. If the expression assigned to `ngIf` evaluates to a false
27012  * value then the element is removed from the DOM, otherwise a clone of the
27013  * element is reinserted into the DOM.
27014  *
27015  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
27016  * element in the DOM rather than changing its visibility via the `display` css property.  A common
27017  * case when this difference is significant is when using css selectors that rely on an element's
27018  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
27019  *
27020  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
27021  * is created when the element is restored.  The scope created within `ngIf` inherits from
27022  * its parent scope using
27023  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
27024  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
27025  * a javascript primitive defined in the parent scope. In this case any modifications made to the
27026  * variable within the child scope will override (hide) the value in the parent scope.
27027  *
27028  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
27029  * is if an element's class attribute is directly modified after it's compiled, using something like
27030  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
27031  * the added class will be lost because the original compiled state is used to regenerate the element.
27032  *
27033  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
27034  * and `leave` effects.
27035  *
27036  * @animations
27037  * | Animation                        | Occurs                               |
27038  * |----------------------------------|-------------------------------------|
27039  * | {@link ng.$animate#enter enter}  | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
27040  * | {@link ng.$animate#leave leave}  | just before the `ngIf` contents are removed from the DOM |
27041  *
27042  * @element ANY
27043  * @scope
27044  * @priority 600
27045  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
27046  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
27047  *     element is added to the DOM tree.
27048  *
27049  * @example
27050   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-if">
27051     <file name="index.html">
27052       <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
27053       Show when checked:
27054       <span ng-if="checked" class="animate-if">
27055         This is removed when the checkbox is unchecked.
27056       </span>
27057     </file>
27058     <file name="animations.css">
27059       .animate-if {
27060         background:white;
27061         border:1px solid black;
27062         padding:10px;
27063       }
27064
27065       .animate-if.ng-enter, .animate-if.ng-leave {
27066         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
27067       }
27068
27069       .animate-if.ng-enter,
27070       .animate-if.ng-leave.ng-leave-active {
27071         opacity:0;
27072       }
27073
27074       .animate-if.ng-leave,
27075       .animate-if.ng-enter.ng-enter-active {
27076         opacity:1;
27077       }
27078     </file>
27079   </example>
27080  */
27081 var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
27082   return {
27083     multiElement: true,
27084     transclude: 'element',
27085     priority: 600,
27086     terminal: true,
27087     restrict: 'A',
27088     $$tlb: true,
27089     link: function($scope, $element, $attr, ctrl, $transclude) {
27090         var block, childScope, previousElements;
27091         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
27092
27093           if (value) {
27094             if (!childScope) {
27095               $transclude(function(clone, newScope) {
27096                 childScope = newScope;
27097                 clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
27098                 // Note: We only need the first/last node of the cloned nodes.
27099                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27100                 // by a directive with templateUrl when its template arrives.
27101                 block = {
27102                   clone: clone
27103                 };
27104                 $animate.enter(clone, $element.parent(), $element);
27105               });
27106             }
27107           } else {
27108             if (previousElements) {
27109               previousElements.remove();
27110               previousElements = null;
27111             }
27112             if (childScope) {
27113               childScope.$destroy();
27114               childScope = null;
27115             }
27116             if (block) {
27117               previousElements = getBlockNodes(block.clone);
27118               $animate.leave(previousElements).done(function(response) {
27119                 if (response !== false) previousElements = null;
27120               });
27121               block = null;
27122             }
27123           }
27124         });
27125     }
27126   };
27127 }];
27128
27129 /**
27130  * @ngdoc directive
27131  * @name ngInclude
27132  * @restrict ECA
27133  *
27134  * @description
27135  * Fetches, compiles and includes an external HTML fragment.
27136  *
27137  * By default, the template URL is restricted to the same domain and protocol as the
27138  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
27139  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
27140  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
27141  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
27142  * ng.$sce Strict Contextual Escaping}.
27143  *
27144  * In addition, the browser's
27145  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
27146  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
27147  * policy may further restrict whether the template is successfully loaded.
27148  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
27149  * access on some browsers.
27150  *
27151  * @animations
27152  * | Animation                        | Occurs                              |
27153  * |----------------------------------|-------------------------------------|
27154  * | {@link ng.$animate#enter enter}  | when the expression changes, on the new include |
27155  * | {@link ng.$animate#leave leave}  | when the expression changes, on the old include |
27156  *
27157  * The enter and leave animation occur concurrently.
27158  *
27159  * @scope
27160  * @priority 400
27161  *
27162  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
27163  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
27164  * @param {string=} onload Expression to evaluate when a new partial is loaded.
27165  *                  <div class="alert alert-warning">
27166  *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
27167  *                  a function with the name on the window element, which will usually throw a
27168  *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
27169  *                  different form that {@link guide/directive#normalization matches} `onload`.
27170  *                  </div>
27171    *
27172  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
27173  *                  $anchorScroll} to scroll the viewport after the content is loaded.
27174  *
27175  *                  - If the attribute is not set, disable scrolling.
27176  *                  - If the attribute is set without value, enable scrolling.
27177  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
27178  *
27179  * @example
27180   <example module="includeExample" deps="angular-animate.js" animations="true" name="ng-include">
27181     <file name="index.html">
27182      <div ng-controller="ExampleController">
27183        <select ng-model="template" ng-options="t.name for t in templates">
27184         <option value="">(blank)</option>
27185        </select>
27186        url of the template: <code>{{template.url}}</code>
27187        <hr/>
27188        <div class="slide-animate-container">
27189          <div class="slide-animate" ng-include="template.url"></div>
27190        </div>
27191      </div>
27192     </file>
27193     <file name="script.js">
27194       angular.module('includeExample', ['ngAnimate'])
27195         .controller('ExampleController', ['$scope', function($scope) {
27196           $scope.templates =
27197             [{ name: 'template1.html', url: 'template1.html'},
27198              { name: 'template2.html', url: 'template2.html'}];
27199           $scope.template = $scope.templates[0];
27200         }]);
27201      </file>
27202     <file name="template1.html">
27203       Content of template1.html
27204     </file>
27205     <file name="template2.html">
27206       Content of template2.html
27207     </file>
27208     <file name="animations.css">
27209       .slide-animate-container {
27210         position:relative;
27211         background:white;
27212         border:1px solid black;
27213         height:40px;
27214         overflow:hidden;
27215       }
27216
27217       .slide-animate {
27218         padding:10px;
27219       }
27220
27221       .slide-animate.ng-enter, .slide-animate.ng-leave {
27222         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
27223
27224         position:absolute;
27225         top:0;
27226         left:0;
27227         right:0;
27228         bottom:0;
27229         display:block;
27230         padding:10px;
27231       }
27232
27233       .slide-animate.ng-enter {
27234         top:-50px;
27235       }
27236       .slide-animate.ng-enter.ng-enter-active {
27237         top:0;
27238       }
27239
27240       .slide-animate.ng-leave {
27241         top:0;
27242       }
27243       .slide-animate.ng-leave.ng-leave-active {
27244         top:50px;
27245       }
27246     </file>
27247     <file name="protractor.js" type="protractor">
27248       var templateSelect = element(by.model('template'));
27249       var includeElem = element(by.css('[ng-include]'));
27250
27251       it('should load template1.html', function() {
27252         expect(includeElem.getText()).toMatch(/Content of template1.html/);
27253       });
27254
27255       it('should load template2.html', function() {
27256         if (browser.params.browser === 'firefox') {
27257           // Firefox can't handle using selects
27258           // See https://github.com/angular/protractor/issues/480
27259           return;
27260         }
27261         templateSelect.click();
27262         templateSelect.all(by.css('option')).get(2).click();
27263         expect(includeElem.getText()).toMatch(/Content of template2.html/);
27264       });
27265
27266       it('should change to blank', function() {
27267         if (browser.params.browser === 'firefox') {
27268           // Firefox can't handle using selects
27269           return;
27270         }
27271         templateSelect.click();
27272         templateSelect.all(by.css('option')).get(0).click();
27273         expect(includeElem.isPresent()).toBe(false);
27274       });
27275     </file>
27276   </example>
27277  */
27278
27279
27280 /**
27281  * @ngdoc event
27282  * @name ngInclude#$includeContentRequested
27283  * @eventType emit on the scope ngInclude was declared in
27284  * @description
27285  * Emitted every time the ngInclude content is requested.
27286  *
27287  * @param {Object} angularEvent Synthetic event object.
27288  * @param {String} src URL of content to load.
27289  */
27290
27291
27292 /**
27293  * @ngdoc event
27294  * @name ngInclude#$includeContentLoaded
27295  * @eventType emit on the current ngInclude scope
27296  * @description
27297  * Emitted every time the ngInclude content is reloaded.
27298  *
27299  * @param {Object} angularEvent Synthetic event object.
27300  * @param {String} src URL of content to load.
27301  */
27302
27303
27304 /**
27305  * @ngdoc event
27306  * @name ngInclude#$includeContentError
27307  * @eventType emit on the scope ngInclude was declared in
27308  * @description
27309  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
27310  *
27311  * @param {Object} angularEvent Synthetic event object.
27312  * @param {String} src URL of content to load.
27313  */
27314 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
27315                   function($templateRequest,   $anchorScroll,   $animate) {
27316   return {
27317     restrict: 'ECA',
27318     priority: 400,
27319     terminal: true,
27320     transclude: 'element',
27321     controller: angular.noop,
27322     compile: function(element, attr) {
27323       var srcExp = attr.ngInclude || attr.src,
27324           onloadExp = attr.onload || '',
27325           autoScrollExp = attr.autoscroll;
27326
27327       return function(scope, $element, $attr, ctrl, $transclude) {
27328         var changeCounter = 0,
27329             currentScope,
27330             previousElement,
27331             currentElement;
27332
27333         var cleanupLastIncludeContent = function() {
27334           if (previousElement) {
27335             previousElement.remove();
27336             previousElement = null;
27337           }
27338           if (currentScope) {
27339             currentScope.$destroy();
27340             currentScope = null;
27341           }
27342           if (currentElement) {
27343             $animate.leave(currentElement).done(function(response) {
27344               if (response !== false) previousElement = null;
27345             });
27346             previousElement = currentElement;
27347             currentElement = null;
27348           }
27349         };
27350
27351         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
27352           var afterAnimation = function(response) {
27353             if (response !== false && isDefined(autoScrollExp) &&
27354               (!autoScrollExp || scope.$eval(autoScrollExp))) {
27355                 $anchorScroll();
27356             }
27357           };
27358           var thisChangeId = ++changeCounter;
27359
27360           if (src) {
27361             //set the 2nd param to true to ignore the template request error so that the inner
27362             //contents and scope can be cleaned up.
27363             $templateRequest(src, true).then(function(response) {
27364               if (scope.$$destroyed) return;
27365
27366               if (thisChangeId !== changeCounter) return;
27367               var newScope = scope.$new();
27368               ctrl.template = response;
27369
27370               // Note: This will also link all children of ng-include that were contained in the original
27371               // html. If that content contains controllers, ... they could pollute/change the scope.
27372               // However, using ng-include on an element with additional content does not make sense...
27373               // Note: We can't remove them in the cloneAttchFn of $transclude as that
27374               // function is called before linking the content, which would apply child
27375               // directives to non existing elements.
27376               var clone = $transclude(newScope, function(clone) {
27377                 cleanupLastIncludeContent();
27378                 $animate.enter(clone, null, $element).done(afterAnimation);
27379               });
27380
27381               currentScope = newScope;
27382               currentElement = clone;
27383
27384               currentScope.$emit('$includeContentLoaded', src);
27385               scope.$eval(onloadExp);
27386             }, function() {
27387               if (scope.$$destroyed) return;
27388
27389               if (thisChangeId === changeCounter) {
27390                 cleanupLastIncludeContent();
27391                 scope.$emit('$includeContentError', src);
27392               }
27393             });
27394             scope.$emit('$includeContentRequested', src);
27395           } else {
27396             cleanupLastIncludeContent();
27397             ctrl.template = null;
27398           }
27399         });
27400       };
27401     }
27402   };
27403 }];
27404
27405 // This directive is called during the $transclude call of the first `ngInclude` directive.
27406 // It will replace and compile the content of the element with the loaded template.
27407 // We need this directive so that the element content is already filled when
27408 // the link function of another directive on the same element as ngInclude
27409 // is called.
27410 var ngIncludeFillContentDirective = ['$compile',
27411   function($compile) {
27412     return {
27413       restrict: 'ECA',
27414       priority: -400,
27415       require: 'ngInclude',
27416       link: function(scope, $element, $attr, ctrl) {
27417         if (toString.call($element[0]).match(/SVG/)) {
27418           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
27419           // support innerHTML, so detect this here and try to generate the contents
27420           // specially.
27421           $element.empty();
27422           $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
27423               function namespaceAdaptedClone(clone) {
27424             $element.append(clone);
27425           }, {futureParentElement: $element});
27426           return;
27427         }
27428
27429         $element.html(ctrl.template);
27430         $compile($element.contents())(scope);
27431       }
27432     };
27433   }];
27434
27435 /**
27436  * @ngdoc directive
27437  * @name ngInit
27438  * @restrict AC
27439  *
27440  * @description
27441  * The `ngInit` directive allows you to evaluate an expression in the
27442  * current scope.
27443  *
27444  * <div class="alert alert-danger">
27445  * This directive can be abused to add unnecessary amounts of logic into your templates.
27446  * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
27447  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
27448  * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
27449  * rather than `ngInit` to initialize values on a scope.
27450  * </div>
27451  *
27452  * <div class="alert alert-warning">
27453  * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
27454  * sure you have parentheses to ensure correct operator precedence:
27455  * <pre class="prettyprint">
27456  * `<div ng-init="test1 = ($index | toString)"></div>`
27457  * </pre>
27458  * </div>
27459  *
27460  * @priority 450
27461  *
27462  * @element ANY
27463  * @param {expression} ngInit {@link guide/expression Expression} to eval.
27464  *
27465  * @example
27466    <example module="initExample" name="ng-init">
27467      <file name="index.html">
27468    <script>
27469      angular.module('initExample', [])
27470        .controller('ExampleController', ['$scope', function($scope) {
27471          $scope.list = [['a', 'b'], ['c', 'd']];
27472        }]);
27473    </script>
27474    <div ng-controller="ExampleController">
27475      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
27476        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
27477           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
27478        </div>
27479      </div>
27480    </div>
27481      </file>
27482      <file name="protractor.js" type="protractor">
27483        it('should alias index positions', function() {
27484          var elements = element.all(by.css('.example-init'));
27485          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
27486          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
27487          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
27488          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
27489        });
27490      </file>
27491    </example>
27492  */
27493 var ngInitDirective = ngDirective({
27494   priority: 450,
27495   compile: function() {
27496     return {
27497       pre: function(scope, element, attrs) {
27498         scope.$eval(attrs.ngInit);
27499       }
27500     };
27501   }
27502 });
27503
27504 /**
27505  * @ngdoc directive
27506  * @name ngList
27507  *
27508  * @description
27509  * Text input that converts between a delimited string and an array of strings. The default
27510  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
27511  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
27512  *
27513  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
27514  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
27515  *   list item is respected. This implies that the user of the directive is responsible for
27516  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
27517  *   tab or newline character.
27518  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
27519  *   when joining the list items back together) and whitespace around each list item is stripped
27520  *   before it is added to the model.
27521  *
27522  * ### Example with Validation
27523  *
27524  * <example name="ngList-directive" module="listExample">
27525  *   <file name="app.js">
27526  *      angular.module('listExample', [])
27527  *        .controller('ExampleController', ['$scope', function($scope) {
27528  *          $scope.names = ['morpheus', 'neo', 'trinity'];
27529  *        }]);
27530  *   </file>
27531  *   <file name="index.html">
27532  *    <form name="myForm" ng-controller="ExampleController">
27533  *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
27534  *      <span role="alert">
27535  *        <span class="error" ng-show="myForm.namesInput.$error.required">
27536  *        Required!</span>
27537  *      </span>
27538  *      <br>
27539  *      <tt>names = {{names}}</tt><br/>
27540  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
27541  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
27542  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27543  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27544  *     </form>
27545  *   </file>
27546  *   <file name="protractor.js" type="protractor">
27547  *     var listInput = element(by.model('names'));
27548  *     var names = element(by.exactBinding('names'));
27549  *     var valid = element(by.binding('myForm.namesInput.$valid'));
27550  *     var error = element(by.css('span.error'));
27551  *
27552  *     it('should initialize to model', function() {
27553  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
27554  *       expect(valid.getText()).toContain('true');
27555  *       expect(error.getCssValue('display')).toBe('none');
27556  *     });
27557  *
27558  *     it('should be invalid if empty', function() {
27559  *       listInput.clear();
27560  *       listInput.sendKeys('');
27561  *
27562  *       expect(names.getText()).toContain('');
27563  *       expect(valid.getText()).toContain('false');
27564  *       expect(error.getCssValue('display')).not.toBe('none');
27565  *     });
27566  *   </file>
27567  * </example>
27568  *
27569  * ### Example - splitting on newline
27570  * <example name="ngList-directive-newlines">
27571  *   <file name="index.html">
27572  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
27573  *    <pre>{{ list | json }}</pre>
27574  *   </file>
27575  *   <file name="protractor.js" type="protractor">
27576  *     it("should split the text by newlines", function() {
27577  *       var listInput = element(by.model('list'));
27578  *       var output = element(by.binding('list | json'));
27579  *       listInput.sendKeys('abc\ndef\nghi');
27580  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
27581  *     });
27582  *   </file>
27583  * </example>
27584  *
27585  * @element input
27586  * @param {string=} ngList optional delimiter that should be used to split the value.
27587  */
27588 var ngListDirective = function() {
27589   return {
27590     restrict: 'A',
27591     priority: 100,
27592     require: 'ngModel',
27593     link: function(scope, element, attr, ctrl) {
27594       // We want to control whitespace trimming so we use this convoluted approach
27595       // to access the ngList attribute, which doesn't pre-trim the attribute
27596       var ngList = element.attr(attr.$attr.ngList) || ', ';
27597       var trimValues = attr.ngTrim !== 'false';
27598       var separator = trimValues ? trim(ngList) : ngList;
27599
27600       var parse = function(viewValue) {
27601         // If the viewValue is invalid (say required but empty) it will be `undefined`
27602         if (isUndefined(viewValue)) return;
27603
27604         var list = [];
27605
27606         if (viewValue) {
27607           forEach(viewValue.split(separator), function(value) {
27608             if (value) list.push(trimValues ? trim(value) : value);
27609           });
27610         }
27611
27612         return list;
27613       };
27614
27615       ctrl.$parsers.push(parse);
27616       ctrl.$formatters.push(function(value) {
27617         if (isArray(value)) {
27618           return value.join(ngList);
27619         }
27620
27621         return undefined;
27622       });
27623
27624       // Override the standard $isEmpty because an empty array means the input is empty.
27625       ctrl.$isEmpty = function(value) {
27626         return !value || !value.length;
27627       };
27628     }
27629   };
27630 };
27631
27632 /* global VALID_CLASS: true,
27633   INVALID_CLASS: true,
27634   PRISTINE_CLASS: true,
27635   DIRTY_CLASS: true,
27636   UNTOUCHED_CLASS: true,
27637   TOUCHED_CLASS: true
27638 */
27639
27640 var VALID_CLASS = 'ng-valid',
27641     INVALID_CLASS = 'ng-invalid',
27642     PRISTINE_CLASS = 'ng-pristine',
27643     DIRTY_CLASS = 'ng-dirty',
27644     UNTOUCHED_CLASS = 'ng-untouched',
27645     TOUCHED_CLASS = 'ng-touched',
27646     PENDING_CLASS = 'ng-pending',
27647     EMPTY_CLASS = 'ng-empty',
27648     NOT_EMPTY_CLASS = 'ng-not-empty';
27649
27650 var ngModelMinErr = minErr('ngModel');
27651
27652 /**
27653  * @ngdoc type
27654  * @name ngModel.NgModelController
27655  *
27656  * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
27657  * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
27658  * is set.
27659  * @property {*} $modelValue The value in the model that the control is bound to.
27660  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
27661        the control reads value from the DOM. The functions are called in array order, each passing
27662        its return value through to the next. The last return value is forwarded to the
27663        {@link ngModel.NgModelController#$validators `$validators`} collection.
27664
27665 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
27666 `$viewValue`}.
27667
27668 Returning `undefined` from a parser means a parse error occurred. In that case,
27669 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
27670 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
27671 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
27672
27673  *
27674  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
27675        the model value changes. The functions are called in reverse array order, each passing the value through to the
27676        next. The last return value is used as the actual DOM value.
27677        Used to format / convert values for display in the control.
27678  * ```js
27679  * function formatter(value) {
27680  *   if (value) {
27681  *     return value.toUpperCase();
27682  *   }
27683  * }
27684  * ngModel.$formatters.push(formatter);
27685  * ```
27686  *
27687  * @property {Object.<string, function>} $validators A collection of validators that are applied
27688  *      whenever the model value changes. The key value within the object refers to the name of the
27689  *      validator while the function refers to the validation operation. The validation operation is
27690  *      provided with the model value as an argument and must return a true or false value depending
27691  *      on the response of that validation.
27692  *
27693  * ```js
27694  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
27695  *   var value = modelValue || viewValue;
27696  *   return /[0-9]+/.test(value) &&
27697  *          /[a-z]+/.test(value) &&
27698  *          /[A-Z]+/.test(value) &&
27699  *          /\W+/.test(value);
27700  * };
27701  * ```
27702  *
27703  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
27704  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
27705  *      is expected to return a promise when it is run during the model validation process. Once the promise
27706  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
27707  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
27708  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
27709  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
27710  *      will only run once all synchronous validators have passed.
27711  *
27712  * Please note that if $http is used then it is important that the server returns a success HTTP response code
27713  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
27714  *
27715  * ```js
27716  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
27717  *   var value = modelValue || viewValue;
27718  *
27719  *   // Lookup user by username
27720  *   return $http.get('/api/users/' + value).
27721  *      then(function resolved() {
27722  *        //username exists, this means validation fails
27723  *        return $q.reject('exists');
27724  *      }, function rejected() {
27725  *        //username does not exist, therefore this validation passes
27726  *        return true;
27727  *      });
27728  * };
27729  * ```
27730  *
27731  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
27732  *     view value has changed. It is called with no arguments, and its return value is ignored.
27733  *     This can be used in place of additional $watches against the model value.
27734  *
27735  * @property {Object} $error An object hash with all failing validator ids as keys.
27736  * @property {Object} $pending An object hash with all pending validator ids as keys.
27737  *
27738  * @property {boolean} $untouched True if control has not lost focus yet.
27739  * @property {boolean} $touched True if control has lost focus.
27740  * @property {boolean} $pristine True if user has not interacted with the control yet.
27741  * @property {boolean} $dirty True if user has already interacted with the control.
27742  * @property {boolean} $valid True if there is no error.
27743  * @property {boolean} $invalid True if at least one error on the control.
27744  * @property {string} $name The name attribute of the control.
27745  *
27746  * @description
27747  *
27748  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
27749  * The controller contains services for data-binding, validation, CSS updates, and value formatting
27750  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
27751  * listening to DOM events.
27752  * Such DOM related logic should be provided by other directives which make use of
27753  * `NgModelController` for data-binding to control elements.
27754  * Angular provides this DOM logic for most {@link input `input`} elements.
27755  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
27756  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
27757  *
27758  * @example
27759  * ### Custom Control Example
27760  * This example shows how to use `NgModelController` with a custom control to achieve
27761  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
27762  * collaborate together to achieve the desired result.
27763  *
27764  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
27765  * contents be edited in place by the user.
27766  *
27767  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
27768  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
27769  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
27770  * that content using the `$sce` service.
27771  *
27772  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
27773     <file name="style.css">
27774       [contenteditable] {
27775         border: 1px solid black;
27776         background-color: white;
27777         min-height: 20px;
27778       }
27779
27780       .ng-invalid {
27781         border: 1px solid red;
27782       }
27783
27784     </file>
27785     <file name="script.js">
27786       angular.module('customControl', ['ngSanitize']).
27787         directive('contenteditable', ['$sce', function($sce) {
27788           return {
27789             restrict: 'A', // only activate on element attribute
27790             require: '?ngModel', // get a hold of NgModelController
27791             link: function(scope, element, attrs, ngModel) {
27792               if (!ngModel) return; // do nothing if no ng-model
27793
27794               // Specify how UI should be updated
27795               ngModel.$render = function() {
27796                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
27797               };
27798
27799               // Listen for change events to enable binding
27800               element.on('blur keyup change', function() {
27801                 scope.$evalAsync(read);
27802               });
27803               read(); // initialize
27804
27805               // Write data to the model
27806               function read() {
27807                 var html = element.html();
27808                 // When we clear the content editable the browser leaves a <br> behind
27809                 // If strip-br attribute is provided then we strip this out
27810                 if (attrs.stripBr && html === '<br>') {
27811                   html = '';
27812                 }
27813                 ngModel.$setViewValue(html);
27814               }
27815             }
27816           };
27817         }]);
27818     </file>
27819     <file name="index.html">
27820       <form name="myForm">
27821        <div contenteditable
27822             name="myWidget" ng-model="userContent"
27823             strip-br="true"
27824             required>Change me!</div>
27825         <span ng-show="myForm.myWidget.$error.required">Required!</span>
27826        <hr>
27827        <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
27828       </form>
27829     </file>
27830     <file name="protractor.js" type="protractor">
27831     it('should data-bind and become invalid', function() {
27832       if (browser.params.browser === 'safari' || browser.params.browser === 'firefox') {
27833         // SafariDriver can't handle contenteditable
27834         // and Firefox driver can't clear contenteditables very well
27835         return;
27836       }
27837       var contentEditable = element(by.css('[contenteditable]'));
27838       var content = 'Change me!';
27839
27840       expect(contentEditable.getText()).toEqual(content);
27841
27842       contentEditable.clear();
27843       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
27844       expect(contentEditable.getText()).toEqual('');
27845       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
27846     });
27847     </file>
27848  * </example>
27849  *
27850  *
27851  */
27852 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
27853     /** @this */ function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
27854   this.$viewValue = Number.NaN;
27855   this.$modelValue = Number.NaN;
27856   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
27857   this.$validators = {};
27858   this.$asyncValidators = {};
27859   this.$parsers = [];
27860   this.$formatters = [];
27861   this.$viewChangeListeners = [];
27862   this.$untouched = true;
27863   this.$touched = false;
27864   this.$pristine = true;
27865   this.$dirty = false;
27866   this.$valid = true;
27867   this.$invalid = false;
27868   this.$error = {}; // keep invalid keys here
27869   this.$$success = {}; // keep valid keys here
27870   this.$pending = undefined; // keep pending keys here
27871   this.$name = $interpolate($attr.name || '', false)($scope);
27872   this.$$parentForm = nullFormCtrl;
27873
27874   var parsedNgModel = $parse($attr.ngModel),
27875       parsedNgModelAssign = parsedNgModel.assign,
27876       ngModelGet = parsedNgModel,
27877       ngModelSet = parsedNgModelAssign,
27878       pendingDebounce = null,
27879       parserValid,
27880       ctrl = this;
27881
27882   this.$$setOptions = function(options) {
27883     ctrl.$options = options;
27884     if (options && options.getterSetter) {
27885       var invokeModelGetter = $parse($attr.ngModel + '()'),
27886           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
27887
27888       ngModelGet = function($scope) {
27889         var modelValue = parsedNgModel($scope);
27890         if (isFunction(modelValue)) {
27891           modelValue = invokeModelGetter($scope);
27892         }
27893         return modelValue;
27894       };
27895       ngModelSet = function($scope, newValue) {
27896         if (isFunction(parsedNgModel($scope))) {
27897           invokeModelSetter($scope, {$$$p: newValue});
27898         } else {
27899           parsedNgModelAssign($scope, newValue);
27900         }
27901       };
27902     } else if (!parsedNgModel.assign) {
27903       throw ngModelMinErr('nonassign', 'Expression \'{0}\' is non-assignable. Element: {1}',
27904           $attr.ngModel, startingTag($element));
27905     }
27906   };
27907
27908   /**
27909    * @ngdoc method
27910    * @name ngModel.NgModelController#$render
27911    *
27912    * @description
27913    * Called when the view needs to be updated. It is expected that the user of the ng-model
27914    * directive will implement this method.
27915    *
27916    * The `$render()` method is invoked in the following situations:
27917    *
27918    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
27919    *   committed value then `$render()` is called to update the input control.
27920    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
27921    *   the `$viewValue` are different from last time.
27922    *
27923    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
27924    * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
27925    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
27926    * invoked if you only change a property on the objects.
27927    */
27928   this.$render = noop;
27929
27930   /**
27931    * @ngdoc method
27932    * @name ngModel.NgModelController#$isEmpty
27933    *
27934    * @description
27935    * This is called when we need to determine if the value of an input is empty.
27936    *
27937    * For instance, the required directive does this to work out if the input has data or not.
27938    *
27939    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
27940    *
27941    * You can override this for input directives whose concept of being empty is different from the
27942    * default. The `checkboxInputType` directive does this because in its case a value of `false`
27943    * implies empty.
27944    *
27945    * @param {*} value The value of the input to check for emptiness.
27946    * @returns {boolean} True if `value` is "empty".
27947    */
27948   this.$isEmpty = function(value) {
27949     // eslint-disable-next-line no-self-compare
27950     return isUndefined(value) || value === '' || value === null || value !== value;
27951   };
27952
27953   this.$$updateEmptyClasses = function(value) {
27954     if (ctrl.$isEmpty(value)) {
27955       $animate.removeClass($element, NOT_EMPTY_CLASS);
27956       $animate.addClass($element, EMPTY_CLASS);
27957     } else {
27958       $animate.removeClass($element, EMPTY_CLASS);
27959       $animate.addClass($element, NOT_EMPTY_CLASS);
27960     }
27961   };
27962
27963
27964   var currentValidationRunId = 0;
27965
27966   /**
27967    * @ngdoc method
27968    * @name ngModel.NgModelController#$setValidity
27969    *
27970    * @description
27971    * Change the validity state, and notify the form.
27972    *
27973    * This method can be called within $parsers/$formatters or a custom validation implementation.
27974    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
27975    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
27976    *
27977    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
27978    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
27979    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
27980    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
27981    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
27982    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
27983    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
27984    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
27985    *                          Skipped is used by Angular when validators do not run because of parse errors and
27986    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
27987    */
27988   addSetValidityMethod({
27989     ctrl: this,
27990     $element: $element,
27991     set: function(object, property) {
27992       object[property] = true;
27993     },
27994     unset: function(object, property) {
27995       delete object[property];
27996     },
27997     $animate: $animate
27998   });
27999
28000   /**
28001    * @ngdoc method
28002    * @name ngModel.NgModelController#$setPristine
28003    *
28004    * @description
28005    * Sets the control to its pristine state.
28006    *
28007    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
28008    * state (`ng-pristine` class). A model is considered to be pristine when the control
28009    * has not been changed from when first compiled.
28010    */
28011   this.$setPristine = function() {
28012     ctrl.$dirty = false;
28013     ctrl.$pristine = true;
28014     $animate.removeClass($element, DIRTY_CLASS);
28015     $animate.addClass($element, PRISTINE_CLASS);
28016   };
28017
28018   /**
28019    * @ngdoc method
28020    * @name ngModel.NgModelController#$setDirty
28021    *
28022    * @description
28023    * Sets the control to its dirty state.
28024    *
28025    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
28026    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
28027    * from when first compiled.
28028    */
28029   this.$setDirty = function() {
28030     ctrl.$dirty = true;
28031     ctrl.$pristine = false;
28032     $animate.removeClass($element, PRISTINE_CLASS);
28033     $animate.addClass($element, DIRTY_CLASS);
28034     ctrl.$$parentForm.$setDirty();
28035   };
28036
28037   /**
28038    * @ngdoc method
28039    * @name ngModel.NgModelController#$setUntouched
28040    *
28041    * @description
28042    * Sets the control to its untouched state.
28043    *
28044    * This method can be called to remove the `ng-touched` class and set the control to its
28045    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
28046    * by default, however this function can be used to restore that state if the model has
28047    * already been touched by the user.
28048    */
28049   this.$setUntouched = function() {
28050     ctrl.$touched = false;
28051     ctrl.$untouched = true;
28052     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
28053   };
28054
28055   /**
28056    * @ngdoc method
28057    * @name ngModel.NgModelController#$setTouched
28058    *
28059    * @description
28060    * Sets the control to its touched state.
28061    *
28062    * This method can be called to remove the `ng-untouched` class and set the control to its
28063    * touched state (`ng-touched` class). A model is considered to be touched when the user has
28064    * first focused the control element and then shifted focus away from the control (blur event).
28065    */
28066   this.$setTouched = function() {
28067     ctrl.$touched = true;
28068     ctrl.$untouched = false;
28069     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
28070   };
28071
28072   /**
28073    * @ngdoc method
28074    * @name ngModel.NgModelController#$rollbackViewValue
28075    *
28076    * @description
28077    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
28078    * which may be caused by a pending debounced event or because the input is waiting for some
28079    * future event.
28080    *
28081    * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
28082    * depend on special events such as `blur`, there can be a period when the `$viewValue` is out of
28083    * sync with the ngModel's `$modelValue`.
28084    *
28085    * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
28086    * and reset the input to the last committed view value.
28087    *
28088    * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
28089    * programmatically before these debounced/future events have resolved/occurred, because Angular's
28090    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
28091    *
28092    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
28093    * input which may have such events pending. This is important in order to make sure that the
28094    * input field will be updated with the new model value and any pending operations are cancelled.
28095    *
28096    * <example name="ng-model-cancel-update" module="cancel-update-example">
28097    *   <file name="app.js">
28098    *     angular.module('cancel-update-example', [])
28099    *
28100    *     .controller('CancelUpdateController', ['$scope', function($scope) {
28101    *       $scope.model = {value1: '', value2: ''};
28102    *
28103    *       $scope.setEmpty = function(e, value, rollback) {
28104    *         if (e.keyCode === 27) {
28105    *           e.preventDefault();
28106    *           if (rollback) {
28107    *             $scope.myForm[value].$rollbackViewValue();
28108    *           }
28109    *           $scope.model[value] = '';
28110    *         }
28111    *       };
28112    *     }]);
28113    *   </file>
28114    *   <file name="index.html">
28115    *     <div ng-controller="CancelUpdateController">
28116    *       <p>Both of these inputs are only updated if they are blurred. Hitting escape should
28117    *       empty them. Follow these steps and observe the difference:</p>
28118    *       <ol>
28119    *         <li>Type something in the input. You will see that the model is not yet updated</li>
28120    *         <li>Press the Escape key.
28121    *           <ol>
28122    *             <li> In the first example, nothing happens, because the model is already '', and no
28123    *             update is detected. If you blur the input, the model will be set to the current view.
28124    *             </li>
28125    *             <li> In the second example, the pending update is cancelled, and the input is set back
28126    *             to the last committed view value (''). Blurring the input does nothing.
28127    *             </li>
28128    *           </ol>
28129    *         </li>
28130    *       </ol>
28131    *
28132    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
28133    *         <div>
28134    *           <p id="inputDescription1">Without $rollbackViewValue():</p>
28135    *           <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
28136    *                  ng-keydown="setEmpty($event, 'value1')">
28137    *           value1: "{{ model.value1 }}"
28138    *         </div>
28139    *
28140    *         <div>
28141    *           <p id="inputDescription2">With $rollbackViewValue():</p>
28142    *           <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
28143    *                  ng-keydown="setEmpty($event, 'value2', true)">
28144    *           value2: "{{ model.value2 }}"
28145    *         </div>
28146    *       </form>
28147    *     </div>
28148    *   </file>
28149        <file name="style.css">
28150           div {
28151             display: table-cell;
28152           }
28153           div:nth-child(1) {
28154             padding-right: 30px;
28155           }
28156
28157         </file>
28158    * </example>
28159    */
28160   this.$rollbackViewValue = function() {
28161     $timeout.cancel(pendingDebounce);
28162     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
28163     ctrl.$render();
28164   };
28165
28166   /**
28167    * @ngdoc method
28168    * @name ngModel.NgModelController#$validate
28169    *
28170    * @description
28171    * Runs each of the registered validators (first synchronous validators and then
28172    * asynchronous validators).
28173    * If the validity changes to invalid, the model will be set to `undefined`,
28174    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
28175    * If the validity changes to valid, it will set the model to the last available valid
28176    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
28177    */
28178   this.$validate = function() {
28179     // ignore $validate before model is initialized
28180     if (isNumberNaN(ctrl.$modelValue)) {
28181       return;
28182     }
28183
28184     var viewValue = ctrl.$$lastCommittedViewValue;
28185     // Note: we use the $$rawModelValue as $modelValue might have been
28186     // set to undefined during a view -> model update that found validation
28187     // errors. We can't parse the view here, since that could change
28188     // the model although neither viewValue nor the model on the scope changed
28189     var modelValue = ctrl.$$rawModelValue;
28190
28191     var prevValid = ctrl.$valid;
28192     var prevModelValue = ctrl.$modelValue;
28193
28194     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
28195
28196     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
28197       // If there was no change in validity, don't update the model
28198       // This prevents changing an invalid modelValue to undefined
28199       if (!allowInvalid && prevValid !== allValid) {
28200         // Note: Don't check ctrl.$valid here, as we could have
28201         // external validators (e.g. calculated on the server),
28202         // that just call $setValidity and need the model value
28203         // to calculate their validity.
28204         ctrl.$modelValue = allValid ? modelValue : undefined;
28205
28206         if (ctrl.$modelValue !== prevModelValue) {
28207           ctrl.$$writeModelToScope();
28208         }
28209       }
28210     });
28211
28212   };
28213
28214   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
28215     currentValidationRunId++;
28216     var localValidationRunId = currentValidationRunId;
28217
28218     // check parser error
28219     if (!processParseErrors()) {
28220       validationDone(false);
28221       return;
28222     }
28223     if (!processSyncValidators()) {
28224       validationDone(false);
28225       return;
28226     }
28227     processAsyncValidators();
28228
28229     function processParseErrors() {
28230       var errorKey = ctrl.$$parserName || 'parse';
28231       if (isUndefined(parserValid)) {
28232         setValidity(errorKey, null);
28233       } else {
28234         if (!parserValid) {
28235           forEach(ctrl.$validators, function(v, name) {
28236             setValidity(name, null);
28237           });
28238           forEach(ctrl.$asyncValidators, function(v, name) {
28239             setValidity(name, null);
28240           });
28241         }
28242         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
28243         setValidity(errorKey, parserValid);
28244         return parserValid;
28245       }
28246       return true;
28247     }
28248
28249     function processSyncValidators() {
28250       var syncValidatorsValid = true;
28251       forEach(ctrl.$validators, function(validator, name) {
28252         var result = validator(modelValue, viewValue);
28253         syncValidatorsValid = syncValidatorsValid && result;
28254         setValidity(name, result);
28255       });
28256       if (!syncValidatorsValid) {
28257         forEach(ctrl.$asyncValidators, function(v, name) {
28258           setValidity(name, null);
28259         });
28260         return false;
28261       }
28262       return true;
28263     }
28264
28265     function processAsyncValidators() {
28266       var validatorPromises = [];
28267       var allValid = true;
28268       forEach(ctrl.$asyncValidators, function(validator, name) {
28269         var promise = validator(modelValue, viewValue);
28270         if (!isPromiseLike(promise)) {
28271           throw ngModelMinErr('nopromise',
28272             'Expected asynchronous validator to return a promise but got \'{0}\' instead.', promise);
28273         }
28274         setValidity(name, undefined);
28275         validatorPromises.push(promise.then(function() {
28276           setValidity(name, true);
28277         }, function() {
28278           allValid = false;
28279           setValidity(name, false);
28280         }));
28281       });
28282       if (!validatorPromises.length) {
28283         validationDone(true);
28284       } else {
28285         $q.all(validatorPromises).then(function() {
28286           validationDone(allValid);
28287         }, noop);
28288       }
28289     }
28290
28291     function setValidity(name, isValid) {
28292       if (localValidationRunId === currentValidationRunId) {
28293         ctrl.$setValidity(name, isValid);
28294       }
28295     }
28296
28297     function validationDone(allValid) {
28298       if (localValidationRunId === currentValidationRunId) {
28299
28300         doneCallback(allValid);
28301       }
28302     }
28303   };
28304
28305   /**
28306    * @ngdoc method
28307    * @name ngModel.NgModelController#$commitViewValue
28308    *
28309    * @description
28310    * Commit a pending update to the `$modelValue`.
28311    *
28312    * Updates may be pending by a debounced event or because the input is waiting for a some future
28313    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
28314    * usually handles calling this in response to input events.
28315    */
28316   this.$commitViewValue = function() {
28317     var viewValue = ctrl.$viewValue;
28318
28319     $timeout.cancel(pendingDebounce);
28320
28321     // If the view value has not changed then we should just exit, except in the case where there is
28322     // a native validator on the element. In this case the validation state may have changed even though
28323     // the viewValue has stayed empty.
28324     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
28325       return;
28326     }
28327     ctrl.$$updateEmptyClasses(viewValue);
28328     ctrl.$$lastCommittedViewValue = viewValue;
28329
28330     // change to dirty
28331     if (ctrl.$pristine) {
28332       this.$setDirty();
28333     }
28334     this.$$parseAndValidate();
28335   };
28336
28337   this.$$parseAndValidate = function() {
28338     var viewValue = ctrl.$$lastCommittedViewValue;
28339     var modelValue = viewValue;
28340     parserValid = isUndefined(modelValue) ? undefined : true;
28341
28342     if (parserValid) {
28343       for (var i = 0; i < ctrl.$parsers.length; i++) {
28344         modelValue = ctrl.$parsers[i](modelValue);
28345         if (isUndefined(modelValue)) {
28346           parserValid = false;
28347           break;
28348         }
28349       }
28350     }
28351     if (isNumberNaN(ctrl.$modelValue)) {
28352       // ctrl.$modelValue has not been touched yet...
28353       ctrl.$modelValue = ngModelGet($scope);
28354     }
28355     var prevModelValue = ctrl.$modelValue;
28356     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
28357     ctrl.$$rawModelValue = modelValue;
28358
28359     if (allowInvalid) {
28360       ctrl.$modelValue = modelValue;
28361       writeToModelIfNeeded();
28362     }
28363
28364     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
28365     // This can happen if e.g. $setViewValue is called from inside a parser
28366     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
28367       if (!allowInvalid) {
28368         // Note: Don't check ctrl.$valid here, as we could have
28369         // external validators (e.g. calculated on the server),
28370         // that just call $setValidity and need the model value
28371         // to calculate their validity.
28372         ctrl.$modelValue = allValid ? modelValue : undefined;
28373         writeToModelIfNeeded();
28374       }
28375     });
28376
28377     function writeToModelIfNeeded() {
28378       if (ctrl.$modelValue !== prevModelValue) {
28379         ctrl.$$writeModelToScope();
28380       }
28381     }
28382   };
28383
28384   this.$$writeModelToScope = function() {
28385     ngModelSet($scope, ctrl.$modelValue);
28386     forEach(ctrl.$viewChangeListeners, function(listener) {
28387       try {
28388         listener();
28389       } catch (e) {
28390         $exceptionHandler(e);
28391       }
28392     });
28393   };
28394
28395   /**
28396    * @ngdoc method
28397    * @name ngModel.NgModelController#$setViewValue
28398    *
28399    * @description
28400    * Update the view value.
28401    *
28402    * This method should be called when a control wants to change the view value; typically,
28403    * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
28404    * directive calls it when the value of the input changes and {@link ng.directive:select select}
28405    * calls it when an option is selected.
28406    *
28407    * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
28408    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
28409    * value sent directly for processing, finally to be applied to `$modelValue` and then the
28410    * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
28411    * in the `$viewChangeListeners` list, are called.
28412    *
28413    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
28414    * and the `default` trigger is not listed, all those actions will remain pending until one of the
28415    * `updateOn` events is triggered on the DOM element.
28416    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
28417    * directive is used with a custom debounce for this particular event.
28418    * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
28419    * is specified, once the timer runs out.
28420    *
28421    * When used with standard inputs, the view value will always be a string (which is in some cases
28422    * parsed into another type, such as a `Date` object for `input[date]`.)
28423    * However, custom controls might also pass objects to this method. In this case, we should make
28424    * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
28425    * perform a deep watch of objects, it only looks for a change of identity. If you only change
28426    * the property of the object then ngModel will not realize that the object has changed and
28427    * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
28428    * not change properties of the copy once it has been passed to `$setViewValue`.
28429    * Otherwise you may cause the model value on the scope to change incorrectly.
28430    *
28431    * <div class="alert alert-info">
28432    * In any case, the value passed to the method should always reflect the current value
28433    * of the control. For example, if you are calling `$setViewValue` for an input element,
28434    * you should pass the input DOM value. Otherwise, the control and the scope model become
28435    * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
28436    * the control's DOM value in any way. If we want to change the control's DOM value
28437    * programmatically, we should update the `ngModel` scope expression. Its new value will be
28438    * picked up by the model controller, which will run it through the `$formatters`, `$render` it
28439    * to update the DOM, and finally call `$validate` on it.
28440    * </div>
28441    *
28442    * @param {*} value value from the view.
28443    * @param {string} trigger Event that triggered the update.
28444    */
28445   this.$setViewValue = function(value, trigger) {
28446     ctrl.$viewValue = value;
28447     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
28448       ctrl.$$debounceViewValueCommit(trigger);
28449     }
28450   };
28451
28452   this.$$debounceViewValueCommit = function(trigger) {
28453     var debounceDelay = 0,
28454         options = ctrl.$options,
28455         debounce;
28456
28457     if (options && isDefined(options.debounce)) {
28458       debounce = options.debounce;
28459       if (isNumber(debounce)) {
28460         debounceDelay = debounce;
28461       } else if (isNumber(debounce[trigger])) {
28462         debounceDelay = debounce[trigger];
28463       } else if (isNumber(debounce['default'])) {
28464         debounceDelay = debounce['default'];
28465       }
28466     }
28467
28468     $timeout.cancel(pendingDebounce);
28469     if (debounceDelay) {
28470       pendingDebounce = $timeout(function() {
28471         ctrl.$commitViewValue();
28472       }, debounceDelay);
28473     } else if ($rootScope.$$phase) {
28474       ctrl.$commitViewValue();
28475     } else {
28476       $scope.$apply(function() {
28477         ctrl.$commitViewValue();
28478       });
28479     }
28480   };
28481
28482   // model -> value
28483   // Note: we cannot use a normal scope.$watch as we want to detect the following:
28484   // 1. scope value is 'a'
28485   // 2. user enters 'b'
28486   // 3. ng-change kicks in and reverts scope value to 'a'
28487   //    -> scope value did not change since the last digest as
28488   //       ng-change executes in apply phase
28489   // 4. view should be changed back to 'a'
28490   $scope.$watch(function ngModelWatch() {
28491     var modelValue = ngModelGet($scope);
28492
28493     // if scope model value and ngModel value are out of sync
28494     // TODO(perf): why not move this to the action fn?
28495     if (modelValue !== ctrl.$modelValue &&
28496        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
28497         // eslint-disable-next-line no-self-compare
28498        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
28499     ) {
28500       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
28501       parserValid = undefined;
28502
28503       var formatters = ctrl.$formatters,
28504           idx = formatters.length;
28505
28506       var viewValue = modelValue;
28507       while (idx--) {
28508         viewValue = formatters[idx](viewValue);
28509       }
28510       if (ctrl.$viewValue !== viewValue) {
28511         ctrl.$$updateEmptyClasses(viewValue);
28512         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
28513         ctrl.$render();
28514
28515         // It is possible that model and view value have been updated during render
28516         ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop);
28517       }
28518     }
28519
28520     return modelValue;
28521   });
28522 }];
28523
28524
28525 /**
28526  * @ngdoc directive
28527  * @name ngModel
28528  *
28529  * @element input
28530  * @priority 1
28531  *
28532  * @description
28533  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
28534  * property on the scope using {@link ngModel.NgModelController NgModelController},
28535  * which is created and exposed by this directive.
28536  *
28537  * `ngModel` is responsible for:
28538  *
28539  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
28540  *   require.
28541  * - Providing validation behavior (i.e. required, number, email, url).
28542  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
28543  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
28544  *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
28545  * - Registering the control with its parent {@link ng.directive:form form}.
28546  *
28547  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
28548  * current scope. If the property doesn't already exist on this scope, it will be created
28549  * implicitly and added to the scope.
28550  *
28551  * For best practices on using `ngModel`, see:
28552  *
28553  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
28554  *
28555  * For basic examples, how to use `ngModel`, see:
28556  *
28557  *  - {@link ng.directive:input input}
28558  *    - {@link input[text] text}
28559  *    - {@link input[checkbox] checkbox}
28560  *    - {@link input[radio] radio}
28561  *    - {@link input[number] number}
28562  *    - {@link input[email] email}
28563  *    - {@link input[url] url}
28564  *    - {@link input[date] date}
28565  *    - {@link input[datetime-local] datetime-local}
28566  *    - {@link input[time] time}
28567  *    - {@link input[month] month}
28568  *    - {@link input[week] week}
28569  *  - {@link ng.directive:select select}
28570  *  - {@link ng.directive:textarea textarea}
28571  *
28572  * # Complex Models (objects or collections)
28573  *
28574  * By default, `ngModel` watches the model by reference, not value. This is important to know when
28575  * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
28576  * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
28577  *
28578  * The model must be assigned an entirely new object or collection before a re-rendering will occur.
28579  *
28580  * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
28581  * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
28582  * if the select is given the `multiple` attribute.
28583  *
28584  * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
28585  * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
28586  * not trigger a re-rendering of the model.
28587  *
28588  * # CSS classes
28589  * The following CSS classes are added and removed on the associated input/select/textarea element
28590  * depending on the validity of the model.
28591  *
28592  *  - `ng-valid`: the model is valid
28593  *  - `ng-invalid`: the model is invalid
28594  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
28595  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
28596  *  - `ng-pristine`: the control hasn't been interacted with yet
28597  *  - `ng-dirty`: the control has been interacted with
28598  *  - `ng-touched`: the control has been blurred
28599  *  - `ng-untouched`: the control hasn't been blurred
28600  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
28601  *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
28602  *     by the {@link ngModel.NgModelController#$isEmpty} method
28603  *  - `ng-not-empty`: the view contains a non-empty value
28604  *
28605  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
28606  *
28607  * ## Animation Hooks
28608  *
28609  * Animations within models are triggered when any of the associated CSS classes are added and removed
28610  * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
28611  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
28612  * The animations that are triggered within ngModel are similar to how they work in ngClass and
28613  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
28614  *
28615  * The following example shows a simple way to utilize CSS transitions to style an input element
28616  * that has been rendered as invalid after it has been validated:
28617  *
28618  * <pre>
28619  * //be sure to include ngAnimate as a module to hook into more
28620  * //advanced animations
28621  * .my-input {
28622  *   transition:0.5s linear all;
28623  *   background: white;
28624  * }
28625  * .my-input.ng-invalid {
28626  *   background: red;
28627  *   color:white;
28628  * }
28629  * </pre>
28630  *
28631  * @example
28632  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample" name="ng-model">
28633      <file name="index.html">
28634        <script>
28635         angular.module('inputExample', [])
28636           .controller('ExampleController', ['$scope', function($scope) {
28637             $scope.val = '1';
28638           }]);
28639        </script>
28640        <style>
28641          .my-input {
28642            transition:all linear 0.5s;
28643            background: transparent;
28644          }
28645          .my-input.ng-invalid {
28646            color:white;
28647            background: red;
28648          }
28649        </style>
28650        <p id="inputDescription">
28651         Update input to see transitions when valid/invalid.
28652         Integer is a valid value.
28653        </p>
28654        <form name="testForm" ng-controller="ExampleController">
28655          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
28656                 aria-describedby="inputDescription" />
28657        </form>
28658      </file>
28659  * </example>
28660  *
28661  * ## Binding to a getter/setter
28662  *
28663  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
28664  * function that returns a representation of the model when called with zero arguments, and sets
28665  * the internal state of a model when called with an argument. It's sometimes useful to use this
28666  * for models that have an internal representation that's different from what the model exposes
28667  * to the view.
28668  *
28669  * <div class="alert alert-success">
28670  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
28671  * frequently than other parts of your code.
28672  * </div>
28673  *
28674  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
28675  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
28676  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
28677  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
28678  *
28679  * The following example shows how to use `ngModel` with a getter/setter:
28680  *
28681  * @example
28682  * <example name="ngModel-getter-setter" module="getterSetterExample">
28683      <file name="index.html">
28684        <div ng-controller="ExampleController">
28685          <form name="userForm">
28686            <label>Name:
28687              <input type="text" name="userName"
28688                     ng-model="user.name"
28689                     ng-model-options="{ getterSetter: true }" />
28690            </label>
28691          </form>
28692          <pre>user.name = <span ng-bind="user.name()"></span></pre>
28693        </div>
28694      </file>
28695      <file name="app.js">
28696        angular.module('getterSetterExample', [])
28697          .controller('ExampleController', ['$scope', function($scope) {
28698            var _name = 'Brian';
28699            $scope.user = {
28700              name: function(newName) {
28701               // Note that newName can be undefined for two reasons:
28702               // 1. Because it is called as a getter and thus called with no arguments
28703               // 2. Because the property should actually be set to undefined. This happens e.g. if the
28704               //    input is invalid
28705               return arguments.length ? (_name = newName) : _name;
28706              }
28707            };
28708          }]);
28709      </file>
28710  * </example>
28711  */
28712 var ngModelDirective = ['$rootScope', function($rootScope) {
28713   return {
28714     restrict: 'A',
28715     require: ['ngModel', '^?form', '^?ngModelOptions'],
28716     controller: NgModelController,
28717     // Prelink needs to run before any input directive
28718     // so that we can set the NgModelOptions in NgModelController
28719     // before anyone else uses it.
28720     priority: 1,
28721     compile: function ngModelCompile(element) {
28722       // Setup initial state of the control
28723       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
28724
28725       return {
28726         pre: function ngModelPreLink(scope, element, attr, ctrls) {
28727           var modelCtrl = ctrls[0],
28728               formCtrl = ctrls[1] || modelCtrl.$$parentForm;
28729
28730           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
28731
28732           // notify others, especially parent forms
28733           formCtrl.$addControl(modelCtrl);
28734
28735           attr.$observe('name', function(newValue) {
28736             if (modelCtrl.$name !== newValue) {
28737               modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
28738             }
28739           });
28740
28741           scope.$on('$destroy', function() {
28742             modelCtrl.$$parentForm.$removeControl(modelCtrl);
28743           });
28744         },
28745         post: function ngModelPostLink(scope, element, attr, ctrls) {
28746           var modelCtrl = ctrls[0];
28747           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
28748             element.on(modelCtrl.$options.updateOn, function(ev) {
28749               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
28750             });
28751           }
28752
28753           element.on('blur', function() {
28754             if (modelCtrl.$touched) return;
28755
28756             if ($rootScope.$$phase) {
28757               scope.$evalAsync(modelCtrl.$setTouched);
28758             } else {
28759               scope.$apply(modelCtrl.$setTouched);
28760             }
28761           });
28762         }
28763       };
28764     }
28765   };
28766 }];
28767
28768
28769
28770 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
28771
28772 /**
28773  * @ngdoc directive
28774  * @name ngModelOptions
28775  *
28776  * @description
28777  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
28778  * events that will trigger a model update and/or a debouncing delay so that the actual update only
28779  * takes place when a timer expires; this timer will be reset after another change takes place.
28780  *
28781  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
28782  * be different from the value in the actual model. This means that if you update the model you
28783  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
28784  * order to make sure it is synchronized with the model and that any debounced action is canceled.
28785  *
28786  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
28787  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
28788  * important because `form` controllers are published to the related scope under the name in their
28789  * `name` attribute.
28790  *
28791  * Any pending changes will take place immediately when an enclosing form is submitted via the
28792  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
28793  * to have access to the updated model.
28794  *
28795  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
28796  *
28797  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
28798  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
28799  *     events using an space delimited list. There is a special event called `default` that
28800  *     matches the default events belonging of the control.
28801  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
28802  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
28803  *     custom value for each event. For example:
28804  *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
28805  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
28806  *     not validate correctly instead of the default behavior of setting the model to undefined.
28807  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
28808        `ngModel` as getters/setters.
28809  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
28810  *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
28811  *     continental US time zone abbreviations, but for general use, use a time zone offset, for
28812  *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
28813  *     If not specified, the timezone of the browser will be used.
28814  *
28815  * @example
28816
28817   The following example shows how to override immediate updates. Changes on the inputs within the
28818   form will update the model only when the control loses focus (blur event). If `escape` key is
28819   pressed while the input field is focused, the value is reset to the value in the current model.
28820
28821   <example name="ngModelOptions-directive-blur" module="optionsExample">
28822     <file name="index.html">
28823       <div ng-controller="ExampleController">
28824         <form name="userForm">
28825           <label>Name:
28826             <input type="text" name="userName"
28827                    ng-model="user.name"
28828                    ng-model-options="{ updateOn: 'blur' }"
28829                    ng-keyup="cancel($event)" />
28830           </label><br />
28831           <label>Other data:
28832             <input type="text" ng-model="user.data" />
28833           </label><br />
28834         </form>
28835         <pre>user.name = <span ng-bind="user.name"></span></pre>
28836         <pre>user.data = <span ng-bind="user.data"></span></pre>
28837       </div>
28838     </file>
28839     <file name="app.js">
28840       angular.module('optionsExample', [])
28841         .controller('ExampleController', ['$scope', function($scope) {
28842           $scope.user = { name: 'John', data: '' };
28843
28844           $scope.cancel = function(e) {
28845             if (e.keyCode === 27) {
28846               $scope.userForm.userName.$rollbackViewValue();
28847             }
28848           };
28849         }]);
28850     </file>
28851     <file name="protractor.js" type="protractor">
28852       var model = element(by.binding('user.name'));
28853       var input = element(by.model('user.name'));
28854       var other = element(by.model('user.data'));
28855
28856       it('should allow custom events', function() {
28857         input.sendKeys(' Doe');
28858         input.click();
28859         expect(model.getText()).toEqual('John');
28860         other.click();
28861         expect(model.getText()).toEqual('John Doe');
28862       });
28863
28864       it('should $rollbackViewValue when model changes', function() {
28865         input.sendKeys(' Doe');
28866         expect(input.getAttribute('value')).toEqual('John Doe');
28867         input.sendKeys(protractor.Key.ESCAPE);
28868         expect(input.getAttribute('value')).toEqual('John');
28869         other.click();
28870         expect(model.getText()).toEqual('John');
28871       });
28872     </file>
28873   </example>
28874
28875   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
28876   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
28877
28878   <example name="ngModelOptions-directive-debounce" module="optionsExample">
28879     <file name="index.html">
28880       <div ng-controller="ExampleController">
28881         <form name="userForm">
28882           <label>Name:
28883             <input type="text" name="userName"
28884                    ng-model="user.name"
28885                    ng-model-options="{ debounce: 1000 }" />
28886           </label>
28887           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
28888           <br />
28889         </form>
28890         <pre>user.name = <span ng-bind="user.name"></span></pre>
28891       </div>
28892     </file>
28893     <file name="app.js">
28894       angular.module('optionsExample', [])
28895         .controller('ExampleController', ['$scope', function($scope) {
28896           $scope.user = { name: 'Igor' };
28897         }]);
28898     </file>
28899   </example>
28900
28901   This one shows how to bind to getter/setters:
28902
28903   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
28904     <file name="index.html">
28905       <div ng-controller="ExampleController">
28906         <form name="userForm">
28907           <label>Name:
28908             <input type="text" name="userName"
28909                    ng-model="user.name"
28910                    ng-model-options="{ getterSetter: true }" />
28911           </label>
28912         </form>
28913         <pre>user.name = <span ng-bind="user.name()"></span></pre>
28914       </div>
28915     </file>
28916     <file name="app.js">
28917       angular.module('getterSetterExample', [])
28918         .controller('ExampleController', ['$scope', function($scope) {
28919           var _name = 'Brian';
28920           $scope.user = {
28921             name: function(newName) {
28922               // Note that newName can be undefined for two reasons:
28923               // 1. Because it is called as a getter and thus called with no arguments
28924               // 2. Because the property should actually be set to undefined. This happens e.g. if the
28925               //    input is invalid
28926               return arguments.length ? (_name = newName) : _name;
28927             }
28928           };
28929         }]);
28930     </file>
28931   </example>
28932  */
28933 var ngModelOptionsDirective = function() {
28934   return {
28935     restrict: 'A',
28936     controller: ['$scope', '$attrs', function NgModelOptionsController($scope, $attrs) {
28937       var that = this;
28938       this.$options = copy($scope.$eval($attrs.ngModelOptions));
28939       // Allow adding/overriding bound events
28940       if (isDefined(this.$options.updateOn)) {
28941         this.$options.updateOnDefault = false;
28942         // extract "default" pseudo-event from list of events that can trigger a model update
28943         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
28944           that.$options.updateOnDefault = true;
28945           return ' ';
28946         }));
28947       } else {
28948         this.$options.updateOnDefault = true;
28949       }
28950     }]
28951   };
28952 };
28953
28954
28955
28956 // helper methods
28957 function addSetValidityMethod(context) {
28958   var ctrl = context.ctrl,
28959       $element = context.$element,
28960       classCache = {},
28961       set = context.set,
28962       unset = context.unset,
28963       $animate = context.$animate;
28964
28965   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
28966
28967   ctrl.$setValidity = setValidity;
28968
28969   function setValidity(validationErrorKey, state, controller) {
28970     if (isUndefined(state)) {
28971       createAndSet('$pending', validationErrorKey, controller);
28972     } else {
28973       unsetAndCleanup('$pending', validationErrorKey, controller);
28974     }
28975     if (!isBoolean(state)) {
28976       unset(ctrl.$error, validationErrorKey, controller);
28977       unset(ctrl.$$success, validationErrorKey, controller);
28978     } else {
28979       if (state) {
28980         unset(ctrl.$error, validationErrorKey, controller);
28981         set(ctrl.$$success, validationErrorKey, controller);
28982       } else {
28983         set(ctrl.$error, validationErrorKey, controller);
28984         unset(ctrl.$$success, validationErrorKey, controller);
28985       }
28986     }
28987     if (ctrl.$pending) {
28988       cachedToggleClass(PENDING_CLASS, true);
28989       ctrl.$valid = ctrl.$invalid = undefined;
28990       toggleValidationCss('', null);
28991     } else {
28992       cachedToggleClass(PENDING_CLASS, false);
28993       ctrl.$valid = isObjectEmpty(ctrl.$error);
28994       ctrl.$invalid = !ctrl.$valid;
28995       toggleValidationCss('', ctrl.$valid);
28996     }
28997
28998     // re-read the state as the set/unset methods could have
28999     // combined state in ctrl.$error[validationError] (used for forms),
29000     // where setting/unsetting only increments/decrements the value,
29001     // and does not replace it.
29002     var combinedState;
29003     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
29004       combinedState = undefined;
29005     } else if (ctrl.$error[validationErrorKey]) {
29006       combinedState = false;
29007     } else if (ctrl.$$success[validationErrorKey]) {
29008       combinedState = true;
29009     } else {
29010       combinedState = null;
29011     }
29012
29013     toggleValidationCss(validationErrorKey, combinedState);
29014     ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
29015   }
29016
29017   function createAndSet(name, value, controller) {
29018     if (!ctrl[name]) {
29019       ctrl[name] = {};
29020     }
29021     set(ctrl[name], value, controller);
29022   }
29023
29024   function unsetAndCleanup(name, value, controller) {
29025     if (ctrl[name]) {
29026       unset(ctrl[name], value, controller);
29027     }
29028     if (isObjectEmpty(ctrl[name])) {
29029       ctrl[name] = undefined;
29030     }
29031   }
29032
29033   function cachedToggleClass(className, switchValue) {
29034     if (switchValue && !classCache[className]) {
29035       $animate.addClass($element, className);
29036       classCache[className] = true;
29037     } else if (!switchValue && classCache[className]) {
29038       $animate.removeClass($element, className);
29039       classCache[className] = false;
29040     }
29041   }
29042
29043   function toggleValidationCss(validationErrorKey, isValid) {
29044     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
29045
29046     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
29047     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
29048   }
29049 }
29050
29051 function isObjectEmpty(obj) {
29052   if (obj) {
29053     for (var prop in obj) {
29054       if (obj.hasOwnProperty(prop)) {
29055         return false;
29056       }
29057     }
29058   }
29059   return true;
29060 }
29061
29062 /**
29063  * @ngdoc directive
29064  * @name ngNonBindable
29065  * @restrict AC
29066  * @priority 1000
29067  *
29068  * @description
29069  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
29070  * DOM element. This is useful if the element contains what appears to be Angular directives and
29071  * bindings but which should be ignored by Angular. This could be the case if you have a site that
29072  * displays snippets of code, for instance.
29073  *
29074  * @element ANY
29075  *
29076  * @example
29077  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
29078  * but the one wrapped in `ngNonBindable` is left alone.
29079  *
29080  * @example
29081     <example name="ng-non-bindable">
29082       <file name="index.html">
29083         <div>Normal: {{1 + 2}}</div>
29084         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
29085       </file>
29086       <file name="protractor.js" type="protractor">
29087        it('should check ng-non-bindable', function() {
29088          expect(element(by.binding('1 + 2')).getText()).toContain('3');
29089          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
29090        });
29091       </file>
29092     </example>
29093  */
29094 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
29095
29096 /* exported ngOptionsDirective */
29097
29098 /* global jqLiteRemove */
29099
29100 var ngOptionsMinErr = minErr('ngOptions');
29101
29102 /**
29103  * @ngdoc directive
29104  * @name ngOptions
29105  * @restrict A
29106  *
29107  * @description
29108  *
29109  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
29110  * elements for the `<select>` element using the array or object obtained by evaluating the
29111  * `ngOptions` comprehension expression.
29112  *
29113  * In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements
29114  * instead of `ngOptions` to achieve a similar result.
29115  * However, `ngOptions` provides some benefits such as reducing memory and
29116  * increasing speed by not creating a new scope for each repeated instance, as well as providing
29117  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
29118  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
29119  *  to a non-string value. This is because an option element can only be bound to string values at
29120  * present.
29121  *
29122  * When an item in the `<select>` menu is selected, the array element or object property
29123  * represented by the selected option will be bound to the model identified by the `ngModel`
29124  * directive.
29125  *
29126  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
29127  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
29128  * option. See example below for demonstration.
29129  *
29130  * ## Complex Models (objects or collections)
29131  *
29132  * By default, `ngModel` watches the model by reference, not value. This is important to know when
29133  * binding the select to a model that is an object or a collection.
29134  *
29135  * One issue occurs if you want to preselect an option. For example, if you set
29136  * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
29137  * because the objects are not identical. So by default, you should always reference the item in your collection
29138  * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
29139  *
29140  * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
29141  * of the item not by reference, but by the result of the `track by` expression. For example, if your
29142  * collection items have an id property, you would `track by item.id`.
29143  *
29144  * A different issue with objects or collections is that ngModel won't detect if an object property or
29145  * a collection item changes. For that reason, `ngOptions` additionally watches the model using
29146  * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
29147  * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
29148  * has not changed identity, but only a property on the object or an item in the collection changes.
29149  *
29150  * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
29151  * if the model is an array). This means that changing a property deeper than the first level inside the
29152  * object/collection will not trigger a re-rendering.
29153  *
29154  * ## `select` **`as`**
29155  *
29156  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
29157  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
29158  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
29159  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
29160  *
29161  *
29162  * ### `select` **`as`** and **`track by`**
29163  *
29164  * <div class="alert alert-warning">
29165  * Be careful when using `select` **`as`** and **`track by`** in the same expression.
29166  * </div>
29167  *
29168  * Given this array of items on the $scope:
29169  *
29170  * ```js
29171  * $scope.items = [{
29172  *   id: 1,
29173  *   label: 'aLabel',
29174  *   subItem: { name: 'aSubItem' }
29175  * }, {
29176  *   id: 2,
29177  *   label: 'bLabel',
29178  *   subItem: { name: 'bSubItem' }
29179  * }];
29180  * ```
29181  *
29182  * This will work:
29183  *
29184  * ```html
29185  * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
29186  * ```
29187  * ```js
29188  * $scope.selected = $scope.items[0];
29189  * ```
29190  *
29191  * but this will not work:
29192  *
29193  * ```html
29194  * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
29195  * ```
29196  * ```js
29197  * $scope.selected = $scope.items[0].subItem;
29198  * ```
29199  *
29200  * In both examples, the **`track by`** expression is applied successfully to each `item` in the
29201  * `items` array. Because the selected option has been set programmatically in the controller, the
29202  * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
29203  * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
29204  * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
29205  * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
29206  * is not matched against any `<option>` and the `<select>` appears as having no selected value.
29207  *
29208  *
29209  * @param {string} ngModel Assignable angular expression to data-bind to.
29210  * @param {string=} name Property name of the form under which the control is published.
29211  * @param {string=} required The control is considered valid only if value is entered.
29212  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29213  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
29214  *    `required` when you want to data-bind to the `required` attribute.
29215  * @param {comprehension_expression=} ngOptions in one of the following forms:
29216  *
29217  *   * for array data sources:
29218  *     * `label` **`for`** `value` **`in`** `array`
29219  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
29220  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
29221  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
29222  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
29223  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
29224  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
29225  *        (for including a filter with `track by`)
29226  *   * for object data sources:
29227  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
29228  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
29229  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
29230  *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
29231  *     * `select` **`as`** `label` **`group by`** `group`
29232  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
29233  *     * `select` **`as`** `label` **`disable when`** `disable`
29234  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
29235  *
29236  * Where:
29237  *
29238  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
29239  *   * `value`: local variable which will refer to each item in the `array` or each property value
29240  *      of `object` during iteration.
29241  *   * `key`: local variable which will refer to a property name in `object` during iteration.
29242  *   * `label`: The result of this expression will be the label for `<option>` element. The
29243  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
29244  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
29245  *      element. If not specified, `select` expression will default to `value`.
29246  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
29247  *      DOM element.
29248  *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
29249  *      element. Return `true` to disable.
29250  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
29251  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
29252  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
29253  *      even when the options are recreated (e.g. reloaded from the server).
29254  *
29255  * @example
29256     <example module="selectExample" name="select">
29257       <file name="index.html">
29258         <script>
29259         angular.module('selectExample', [])
29260           .controller('ExampleController', ['$scope', function($scope) {
29261             $scope.colors = [
29262               {name:'black', shade:'dark'},
29263               {name:'white', shade:'light', notAnOption: true},
29264               {name:'red', shade:'dark'},
29265               {name:'blue', shade:'dark', notAnOption: true},
29266               {name:'yellow', shade:'light', notAnOption: false}
29267             ];
29268             $scope.myColor = $scope.colors[2]; // red
29269           }]);
29270         </script>
29271         <div ng-controller="ExampleController">
29272           <ul>
29273             <li ng-repeat="color in colors">
29274               <label>Name: <input ng-model="color.name"></label>
29275               <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
29276               <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
29277             </li>
29278             <li>
29279               <button ng-click="colors.push({})">add</button>
29280             </li>
29281           </ul>
29282           <hr/>
29283           <label>Color (null not allowed):
29284             <select ng-model="myColor" ng-options="color.name for color in colors"></select>
29285           </label><br/>
29286           <label>Color (null allowed):
29287           <span  class="nullable">
29288             <select ng-model="myColor" ng-options="color.name for color in colors">
29289               <option value="">-- choose color --</option>
29290             </select>
29291           </span></label><br/>
29292
29293           <label>Color grouped by shade:
29294             <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
29295             </select>
29296           </label><br/>
29297
29298           <label>Color grouped by shade, with some disabled:
29299             <select ng-model="myColor"
29300                   ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
29301             </select>
29302           </label><br/>
29303
29304
29305
29306           Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
29307           <br/>
29308           <hr/>
29309           Currently selected: {{ {selected_color:myColor} }}
29310           <div style="border:solid 1px black; height:20px"
29311                ng-style="{'background-color':myColor.name}">
29312           </div>
29313         </div>
29314       </file>
29315       <file name="protractor.js" type="protractor">
29316          it('should check ng-options', function() {
29317            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
29318            element.all(by.model('myColor')).first().click();
29319            element.all(by.css('select[ng-model="myColor"] option')).first().click();
29320            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
29321            element(by.css('.nullable select[ng-model="myColor"]')).click();
29322            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
29323            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
29324          });
29325       </file>
29326     </example>
29327  */
29328
29329 /* eslint-disable max-len */
29330 //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555000000000666666666666600000007777777777777000000000000000888888888800000000000000000009999999999
29331 var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\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]+?))?$/;
29332                         // 1: value expression (valueFn)
29333                         // 2: label expression (displayFn)
29334                         // 3: group by expression (groupByFn)
29335                         // 4: disable when expression (disableWhenFn)
29336                         // 5: array item variable name
29337                         // 6: object item key variable name
29338                         // 7: object item value variable name
29339                         // 8: collection expression
29340                         // 9: track by expression
29341 /* eslint-enable */
29342
29343
29344 var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
29345
29346   function parseOptionsExpression(optionsExp, selectElement, scope) {
29347
29348     var match = optionsExp.match(NG_OPTIONS_REGEXP);
29349     if (!(match)) {
29350       throw ngOptionsMinErr('iexp',
29351         'Expected expression in form of ' +
29352         '\'_select_ (as _label_)? for (_key_,)?_value_ in _collection_\'' +
29353         ' but got \'{0}\'. Element: {1}',
29354         optionsExp, startingTag(selectElement));
29355     }
29356
29357     // Extract the parts from the ngOptions expression
29358
29359     // The variable name for the value of the item in the collection
29360     var valueName = match[5] || match[7];
29361     // The variable name for the key of the item in the collection
29362     var keyName = match[6];
29363
29364     // An expression that generates the viewValue for an option if there is a label expression
29365     var selectAs = / as /.test(match[0]) && match[1];
29366     // An expression that is used to track the id of each object in the options collection
29367     var trackBy = match[9];
29368     // An expression that generates the viewValue for an option if there is no label expression
29369     var valueFn = $parse(match[2] ? match[1] : valueName);
29370     var selectAsFn = selectAs && $parse(selectAs);
29371     var viewValueFn = selectAsFn || valueFn;
29372     var trackByFn = trackBy && $parse(trackBy);
29373
29374     // Get the value by which we are going to track the option
29375     // if we have a trackFn then use that (passing scope and locals)
29376     // otherwise just hash the given viewValue
29377     var getTrackByValueFn = trackBy ?
29378                               function(value, locals) { return trackByFn(scope, locals); } :
29379                               function getHashOfValue(value) { return hashKey(value); };
29380     var getTrackByValue = function(value, key) {
29381       return getTrackByValueFn(value, getLocals(value, key));
29382     };
29383
29384     var displayFn = $parse(match[2] || match[1]);
29385     var groupByFn = $parse(match[3] || '');
29386     var disableWhenFn = $parse(match[4] || '');
29387     var valuesFn = $parse(match[8]);
29388
29389     var locals = {};
29390     var getLocals = keyName ? function(value, key) {
29391       locals[keyName] = key;
29392       locals[valueName] = value;
29393       return locals;
29394     } : function(value) {
29395       locals[valueName] = value;
29396       return locals;
29397     };
29398
29399
29400     function Option(selectValue, viewValue, label, group, disabled) {
29401       this.selectValue = selectValue;
29402       this.viewValue = viewValue;
29403       this.label = label;
29404       this.group = group;
29405       this.disabled = disabled;
29406     }
29407
29408     function getOptionValuesKeys(optionValues) {
29409       var optionValuesKeys;
29410
29411       if (!keyName && isArrayLike(optionValues)) {
29412         optionValuesKeys = optionValues;
29413       } else {
29414         // if object, extract keys, in enumeration order, unsorted
29415         optionValuesKeys = [];
29416         for (var itemKey in optionValues) {
29417           if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
29418             optionValuesKeys.push(itemKey);
29419           }
29420         }
29421       }
29422       return optionValuesKeys;
29423     }
29424
29425     return {
29426       trackBy: trackBy,
29427       getTrackByValue: getTrackByValue,
29428       getWatchables: $parse(valuesFn, function(optionValues) {
29429         // Create a collection of things that we would like to watch (watchedArray)
29430         // so that they can all be watched using a single $watchCollection
29431         // that only runs the handler once if anything changes
29432         var watchedArray = [];
29433         optionValues = optionValues || [];
29434
29435         var optionValuesKeys = getOptionValuesKeys(optionValues);
29436         var optionValuesLength = optionValuesKeys.length;
29437         for (var index = 0; index < optionValuesLength; index++) {
29438           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
29439           var value = optionValues[key];
29440
29441           var locals = getLocals(value, key);
29442           var selectValue = getTrackByValueFn(value, locals);
29443           watchedArray.push(selectValue);
29444
29445           // Only need to watch the displayFn if there is a specific label expression
29446           if (match[2] || match[1]) {
29447             var label = displayFn(scope, locals);
29448             watchedArray.push(label);
29449           }
29450
29451           // Only need to watch the disableWhenFn if there is a specific disable expression
29452           if (match[4]) {
29453             var disableWhen = disableWhenFn(scope, locals);
29454             watchedArray.push(disableWhen);
29455           }
29456         }
29457         return watchedArray;
29458       }),
29459
29460       getOptions: function() {
29461
29462         var optionItems = [];
29463         var selectValueMap = {};
29464
29465         // The option values were already computed in the `getWatchables` fn,
29466         // which must have been called to trigger `getOptions`
29467         var optionValues = valuesFn(scope) || [];
29468         var optionValuesKeys = getOptionValuesKeys(optionValues);
29469         var optionValuesLength = optionValuesKeys.length;
29470
29471         for (var index = 0; index < optionValuesLength; index++) {
29472           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
29473           var value = optionValues[key];
29474           var locals = getLocals(value, key);
29475           var viewValue = viewValueFn(scope, locals);
29476           var selectValue = getTrackByValueFn(viewValue, locals);
29477           var label = displayFn(scope, locals);
29478           var group = groupByFn(scope, locals);
29479           var disabled = disableWhenFn(scope, locals);
29480           var optionItem = new Option(selectValue, viewValue, label, group, disabled);
29481
29482           optionItems.push(optionItem);
29483           selectValueMap[selectValue] = optionItem;
29484         }
29485
29486         return {
29487           items: optionItems,
29488           selectValueMap: selectValueMap,
29489           getOptionFromViewValue: function(value) {
29490             return selectValueMap[getTrackByValue(value)];
29491           },
29492           getViewValueFromOption: function(option) {
29493             // If the viewValue could be an object that may be mutated by the application,
29494             // we need to make a copy and not return the reference to the value on the option.
29495             return trackBy ? copy(option.viewValue) : option.viewValue;
29496           }
29497         };
29498       }
29499     };
29500   }
29501
29502
29503   // we can't just jqLite('<option>') since jqLite is not smart enough
29504   // to create it in <select> and IE barfs otherwise.
29505   var optionTemplate = window.document.createElement('option'),
29506       optGroupTemplate = window.document.createElement('optgroup');
29507
29508     function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
29509
29510       var selectCtrl = ctrls[0];
29511       var ngModelCtrl = ctrls[1];
29512       var multiple = attr.multiple;
29513
29514       // The emptyOption allows the application developer to provide their own custom "empty"
29515       // option when the viewValue does not match any of the option values.
29516       var emptyOption;
29517       for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
29518         if (children[i].value === '') {
29519           emptyOption = children.eq(i);
29520           break;
29521         }
29522       }
29523
29524       var providedEmptyOption = !!emptyOption;
29525       var emptyOptionRendered = false;
29526
29527       var unknownOption = jqLite(optionTemplate.cloneNode(false));
29528       unknownOption.val('?');
29529
29530       var options;
29531       var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
29532       // This stores the newly created options before they are appended to the select.
29533       // Since the contents are removed from the fragment when it is appended,
29534       // we only need to create it once.
29535       var listFragment = $document[0].createDocumentFragment();
29536
29537       var renderEmptyOption = function() {
29538         if (!providedEmptyOption) {
29539           selectElement.prepend(emptyOption);
29540         }
29541         selectElement.val('');
29542         if (emptyOptionRendered) {
29543           emptyOption.prop('selected', true); // needed for IE
29544           emptyOption.attr('selected', true);
29545         }
29546       };
29547
29548       var removeEmptyOption = function() {
29549         if (!providedEmptyOption) {
29550           emptyOption.remove();
29551         } else if (emptyOptionRendered) {
29552           emptyOption.removeAttr('selected');
29553         }
29554       };
29555
29556       var renderUnknownOption = function() {
29557         selectElement.prepend(unknownOption);
29558         selectElement.val('?');
29559         unknownOption.prop('selected', true); // needed for IE
29560         unknownOption.attr('selected', true);
29561       };
29562
29563       var removeUnknownOption = function() {
29564         unknownOption.remove();
29565       };
29566
29567       // Update the controller methods for multiple selectable options
29568       if (!multiple) {
29569
29570         selectCtrl.writeValue = function writeNgOptionsValue(value) {
29571           var selectedOption = options.selectValueMap[selectElement.val()];
29572           var option = options.getOptionFromViewValue(value);
29573
29574           // Make sure to remove the selected attribute from the previously selected option
29575           // Otherwise, screen readers might get confused
29576           if (selectedOption) selectedOption.element.removeAttribute('selected');
29577
29578           if (option) {
29579             // Don't update the option when it is already selected.
29580             // For example, the browser will select the first option by default. In that case,
29581             // most properties are set automatically - except the `selected` attribute, which we
29582             // set always
29583
29584             if (selectElement[0].value !== option.selectValue) {
29585               removeUnknownOption();
29586               removeEmptyOption();
29587
29588               selectElement[0].value = option.selectValue;
29589               option.element.selected = true;
29590             }
29591
29592             option.element.setAttribute('selected', 'selected');
29593           } else {
29594             if (value === null || providedEmptyOption) {
29595               removeUnknownOption();
29596               renderEmptyOption();
29597             } else {
29598               removeEmptyOption();
29599               renderUnknownOption();
29600             }
29601           }
29602         };
29603
29604         selectCtrl.readValue = function readNgOptionsValue() {
29605
29606           var selectedOption = options.selectValueMap[selectElement.val()];
29607
29608           if (selectedOption && !selectedOption.disabled) {
29609             removeEmptyOption();
29610             removeUnknownOption();
29611             return options.getViewValueFromOption(selectedOption);
29612           }
29613           return null;
29614         };
29615
29616         // If we are using `track by` then we must watch the tracked value on the model
29617         // since ngModel only watches for object identity change
29618         // FIXME: When a user selects an option, this watch will fire needlessly
29619         if (ngOptions.trackBy) {
29620           scope.$watch(
29621             function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
29622             function() { ngModelCtrl.$render(); }
29623           );
29624         }
29625
29626       } else {
29627
29628         ngModelCtrl.$isEmpty = function(value) {
29629           return !value || value.length === 0;
29630         };
29631
29632
29633         selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
29634           options.items.forEach(function(option) {
29635             option.element.selected = false;
29636           });
29637
29638           if (value) {
29639             value.forEach(function(item) {
29640               var option = options.getOptionFromViewValue(item);
29641               if (option) option.element.selected = true;
29642             });
29643           }
29644         };
29645
29646
29647         selectCtrl.readValue = function readNgOptionsMultiple() {
29648           var selectedValues = selectElement.val() || [],
29649               selections = [];
29650
29651           forEach(selectedValues, function(value) {
29652             var option = options.selectValueMap[value];
29653             if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
29654           });
29655
29656           return selections;
29657         };
29658
29659         // If we are using `track by` then we must watch these tracked values on the model
29660         // since ngModel only watches for object identity change
29661         if (ngOptions.trackBy) {
29662
29663           scope.$watchCollection(function() {
29664             if (isArray(ngModelCtrl.$viewValue)) {
29665               return ngModelCtrl.$viewValue.map(function(value) {
29666                 return ngOptions.getTrackByValue(value);
29667               });
29668             }
29669           }, function() {
29670             ngModelCtrl.$render();
29671           });
29672
29673         }
29674       }
29675
29676
29677       if (providedEmptyOption) {
29678
29679         // we need to remove it before calling selectElement.empty() because otherwise IE will
29680         // remove the label from the element. wtf?
29681         emptyOption.remove();
29682
29683         // compile the element since there might be bindings in it
29684         $compile(emptyOption)(scope);
29685
29686         if (emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
29687           // This means the empty option has currently no actual DOM node, probably because
29688           // it has been modified by a transclusion directive.
29689
29690           emptyOptionRendered = false;
29691
29692           // Redefine the registerOption function, which will catch
29693           // options that are added by ngIf etc. (rendering of the node is async because of
29694           // lazy transclusion)
29695           selectCtrl.registerOption = function(optionScope, optionEl) {
29696             if (optionEl.val() === '') {
29697               emptyOptionRendered = true;
29698               emptyOption = optionEl;
29699               emptyOption.removeClass('ng-scope');
29700               // This ensures the new empty option is selected if previously no option was selected
29701               ngModelCtrl.$render();
29702
29703               optionEl.on('$destroy', function() {
29704                 emptyOption = undefined;
29705                 emptyOptionRendered = false;
29706               });
29707             }
29708           };
29709
29710         } else {
29711           emptyOption.removeClass('ng-scope');
29712           emptyOptionRendered = true;
29713         }
29714
29715       } else {
29716         emptyOption = jqLite(optionTemplate.cloneNode(false));
29717       }
29718
29719       selectElement.empty();
29720
29721       // We need to do this here to ensure that the options object is defined
29722       // when we first hit it in writeNgOptionsValue
29723       updateOptions();
29724
29725       // We will re-render the option elements if the option values or labels change
29726       scope.$watchCollection(ngOptions.getWatchables, updateOptions);
29727
29728       // ------------------------------------------------------------------ //
29729
29730       function addOptionElement(option, parent) {
29731         var optionElement = optionTemplate.cloneNode(false);
29732         parent.appendChild(optionElement);
29733         updateOptionElement(option, optionElement);
29734       }
29735
29736
29737       function updateOptionElement(option, element) {
29738         option.element = element;
29739         element.disabled = option.disabled;
29740         // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
29741         // selects in certain circumstances when multiple selects are next to each other and display
29742         // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
29743         // See https://github.com/angular/angular.js/issues/11314 for more info.
29744         // This is unfortunately untestable with unit / e2e tests
29745         if (option.label !== element.label) {
29746           element.label = option.label;
29747           element.textContent = option.label;
29748         }
29749         element.value = option.selectValue;
29750       }
29751
29752       function updateOptions() {
29753         var previousValue = options && selectCtrl.readValue();
29754
29755         // We must remove all current options, but cannot simply set innerHTML = null
29756         // since the providedEmptyOption might have an ngIf on it that inserts comments which we
29757         // must preserve.
29758         // Instead, iterate over the current option elements and remove them or their optgroup
29759         // parents
29760         if (options) {
29761
29762           for (var i = options.items.length - 1; i >= 0; i--) {
29763             var option = options.items[i];
29764             if (isDefined(option.group)) {
29765               jqLiteRemove(option.element.parentNode);
29766             } else {
29767               jqLiteRemove(option.element);
29768             }
29769           }
29770         }
29771
29772         options = ngOptions.getOptions();
29773
29774         var groupElementMap = {};
29775
29776         // Ensure that the empty option is always there if it was explicitly provided
29777         if (providedEmptyOption) {
29778           selectElement.prepend(emptyOption);
29779         }
29780
29781         options.items.forEach(function addOption(option) {
29782           var groupElement;
29783
29784           if (isDefined(option.group)) {
29785
29786             // This option is to live in a group
29787             // See if we have already created this group
29788             groupElement = groupElementMap[option.group];
29789
29790             if (!groupElement) {
29791
29792               groupElement = optGroupTemplate.cloneNode(false);
29793               listFragment.appendChild(groupElement);
29794
29795               // Update the label on the group element
29796               // "null" is special cased because of Safari
29797               groupElement.label = option.group === null ? 'null' : option.group;
29798
29799               // Store it for use later
29800               groupElementMap[option.group] = groupElement;
29801             }
29802
29803             addOptionElement(option, groupElement);
29804
29805           } else {
29806
29807             // This option is not in a group
29808             addOptionElement(option, listFragment);
29809           }
29810         });
29811
29812         selectElement[0].appendChild(listFragment);
29813
29814         ngModelCtrl.$render();
29815
29816         // Check to see if the value has changed due to the update to the options
29817         if (!ngModelCtrl.$isEmpty(previousValue)) {
29818           var nextValue = selectCtrl.readValue();
29819           var isNotPrimitive = ngOptions.trackBy || multiple;
29820           if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
29821             ngModelCtrl.$setViewValue(nextValue);
29822             ngModelCtrl.$render();
29823           }
29824         }
29825
29826       }
29827   }
29828
29829   return {
29830     restrict: 'A',
29831     terminal: true,
29832     require: ['select', 'ngModel'],
29833     link: {
29834       pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
29835         // Deactivate the SelectController.register method to prevent
29836         // option directives from accidentally registering themselves
29837         // (and unwanted $destroy handlers etc.)
29838         ctrls[0].registerOption = noop;
29839       },
29840       post: ngOptionsPostLink
29841     }
29842   };
29843 }];
29844
29845 /**
29846  * @ngdoc directive
29847  * @name ngPluralize
29848  * @restrict EA
29849  *
29850  * @description
29851  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
29852  * These rules are bundled with angular.js, but can be overridden
29853  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
29854  * by specifying the mappings between
29855  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
29856  * and the strings to be displayed.
29857  *
29858  * # Plural categories and explicit number rules
29859  * There are two
29860  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
29861  * in Angular's default en-US locale: "one" and "other".
29862  *
29863  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
29864  * any number that is not 1), an explicit number rule can only match one number. For example, the
29865  * explicit number rule for "3" matches the number 3. There are examples of plural categories
29866  * and explicit number rules throughout the rest of this documentation.
29867  *
29868  * # Configuring ngPluralize
29869  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
29870  * You can also provide an optional attribute, `offset`.
29871  *
29872  * The value of the `count` attribute can be either a string or an {@link guide/expression
29873  * Angular expression}; these are evaluated on the current scope for its bound value.
29874  *
29875  * The `when` attribute specifies the mappings between plural categories and the actual
29876  * string to be displayed. The value of the attribute should be a JSON object.
29877  *
29878  * The following example shows how to configure ngPluralize:
29879  *
29880  * ```html
29881  * <ng-pluralize count="personCount"
29882                  when="{'0': 'Nobody is viewing.',
29883  *                      'one': '1 person is viewing.',
29884  *                      'other': '{} people are viewing.'}">
29885  * </ng-pluralize>
29886  *```
29887  *
29888  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
29889  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
29890  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
29891  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
29892  * show "a dozen people are viewing".
29893  *
29894  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
29895  * into pluralized strings. In the previous example, Angular will replace `{}` with
29896  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
29897  * for <span ng-non-bindable>{{numberExpression}}</span>.
29898  *
29899  * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
29900  * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
29901  *
29902  * # Configuring ngPluralize with offset
29903  * The `offset` attribute allows further customization of pluralized text, which can result in
29904  * a better user experience. For example, instead of the message "4 people are viewing this document",
29905  * you might display "John, Kate and 2 others are viewing this document".
29906  * The offset attribute allows you to offset a number by any desired value.
29907  * Let's take a look at an example:
29908  *
29909  * ```html
29910  * <ng-pluralize count="personCount" offset=2
29911  *               when="{'0': 'Nobody is viewing.',
29912  *                      '1': '{{person1}} is viewing.',
29913  *                      '2': '{{person1}} and {{person2}} are viewing.',
29914  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
29915  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
29916  * </ng-pluralize>
29917  * ```
29918  *
29919  * Notice that we are still using two plural categories(one, other), but we added
29920  * three explicit number rules 0, 1 and 2.
29921  * When one person, perhaps John, views the document, "John is viewing" will be shown.
29922  * When three people view the document, no explicit number rule is found, so
29923  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
29924  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
29925  * is shown.
29926  *
29927  * Note that when you specify offsets, you must provide explicit number rules for
29928  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
29929  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
29930  * plural categories "one" and "other".
29931  *
29932  * @param {string|expression} count The variable to be bound to.
29933  * @param {string} when The mapping between plural category to its corresponding strings.
29934  * @param {number=} offset Offset to deduct from the total number.
29935  *
29936  * @example
29937     <example module="pluralizeExample" name="ng-pluralize">
29938       <file name="index.html">
29939         <script>
29940           angular.module('pluralizeExample', [])
29941             .controller('ExampleController', ['$scope', function($scope) {
29942               $scope.person1 = 'Igor';
29943               $scope.person2 = 'Misko';
29944               $scope.personCount = 1;
29945             }]);
29946         </script>
29947         <div ng-controller="ExampleController">
29948           <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
29949           <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
29950           <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
29951
29952           <!--- Example with simple pluralization rules for en locale --->
29953           Without Offset:
29954           <ng-pluralize count="personCount"
29955                         when="{'0': 'Nobody is viewing.',
29956                                'one': '1 person is viewing.',
29957                                'other': '{} people are viewing.'}">
29958           </ng-pluralize><br>
29959
29960           <!--- Example with offset --->
29961           With Offset(2):
29962           <ng-pluralize count="personCount" offset=2
29963                         when="{'0': 'Nobody is viewing.',
29964                                '1': '{{person1}} is viewing.',
29965                                '2': '{{person1}} and {{person2}} are viewing.',
29966                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
29967                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
29968           </ng-pluralize>
29969         </div>
29970       </file>
29971       <file name="protractor.js" type="protractor">
29972         it('should show correct pluralized string', function() {
29973           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
29974           var withOffset = element.all(by.css('ng-pluralize')).get(1);
29975           var countInput = element(by.model('personCount'));
29976
29977           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
29978           expect(withOffset.getText()).toEqual('Igor is viewing.');
29979
29980           countInput.clear();
29981           countInput.sendKeys('0');
29982
29983           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
29984           expect(withOffset.getText()).toEqual('Nobody is viewing.');
29985
29986           countInput.clear();
29987           countInput.sendKeys('2');
29988
29989           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
29990           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
29991
29992           countInput.clear();
29993           countInput.sendKeys('3');
29994
29995           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
29996           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
29997
29998           countInput.clear();
29999           countInput.sendKeys('4');
30000
30001           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
30002           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
30003         });
30004         it('should show data-bound names', function() {
30005           var withOffset = element.all(by.css('ng-pluralize')).get(1);
30006           var personCount = element(by.model('personCount'));
30007           var person1 = element(by.model('person1'));
30008           var person2 = element(by.model('person2'));
30009           personCount.clear();
30010           personCount.sendKeys('4');
30011           person1.clear();
30012           person1.sendKeys('Di');
30013           person2.clear();
30014           person2.sendKeys('Vojta');
30015           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
30016         });
30017       </file>
30018     </example>
30019  */
30020 var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
30021   var BRACE = /{}/g,
30022       IS_WHEN = /^when(Minus)?(.+)$/;
30023
30024   return {
30025     link: function(scope, element, attr) {
30026       var numberExp = attr.count,
30027           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
30028           offset = attr.offset || 0,
30029           whens = scope.$eval(whenExp) || {},
30030           whensExpFns = {},
30031           startSymbol = $interpolate.startSymbol(),
30032           endSymbol = $interpolate.endSymbol(),
30033           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
30034           watchRemover = angular.noop,
30035           lastCount;
30036
30037       forEach(attr, function(expression, attributeName) {
30038         var tmpMatch = IS_WHEN.exec(attributeName);
30039         if (tmpMatch) {
30040           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
30041           whens[whenKey] = element.attr(attr.$attr[attributeName]);
30042         }
30043       });
30044       forEach(whens, function(expression, key) {
30045         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
30046
30047       });
30048
30049       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
30050         var count = parseFloat(newVal);
30051         var countIsNaN = isNumberNaN(count);
30052
30053         if (!countIsNaN && !(count in whens)) {
30054           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
30055           // Otherwise, check it against pluralization rules in $locale service.
30056           count = $locale.pluralCat(count - offset);
30057         }
30058
30059         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
30060         // In JS `NaN !== NaN`, so we have to explicitly check.
30061         if ((count !== lastCount) && !(countIsNaN && isNumberNaN(lastCount))) {
30062           watchRemover();
30063           var whenExpFn = whensExpFns[count];
30064           if (isUndefined(whenExpFn)) {
30065             if (newVal != null) {
30066               $log.debug('ngPluralize: no rule defined for \'' + count + '\' in ' + whenExp);
30067             }
30068             watchRemover = noop;
30069             updateElementText();
30070           } else {
30071             watchRemover = scope.$watch(whenExpFn, updateElementText);
30072           }
30073           lastCount = count;
30074         }
30075       });
30076
30077       function updateElementText(newText) {
30078         element.text(newText || '');
30079       }
30080     }
30081   };
30082 }];
30083
30084 /* exported ngRepeatDirective */
30085
30086 /**
30087  * @ngdoc directive
30088  * @name ngRepeat
30089  * @multiElement
30090  *
30091  * @description
30092  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
30093  * instance gets its own scope, where the given loop variable is set to the current collection item,
30094  * and `$index` is set to the item index or key.
30095  *
30096  * Special properties are exposed on the local scope of each template instance, including:
30097  *
30098  * | Variable  | Type            | Details                                                                     |
30099  * |-----------|-----------------|-----------------------------------------------------------------------------|
30100  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
30101  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
30102  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
30103  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
30104  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
30105  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
30106  *
30107  * <div class="alert alert-info">
30108  *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
30109  *   This may be useful when, for instance, nesting ngRepeats.
30110  * </div>
30111  *
30112  *
30113  * # Iterating over object properties
30114  *
30115  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
30116  * syntax:
30117  *
30118  * ```js
30119  * <div ng-repeat="(key, value) in myObj"> ... </div>
30120  * ```
30121  *
30122  * However, there are a few limitations compared to array iteration:
30123  *
30124  * - The JavaScript specification does not define the order of keys
30125  *   returned for an object, so Angular relies on the order returned by the browser
30126  *   when running `for key in myObj`. Browsers generally follow the strategy of providing
30127  *   keys in the order in which they were defined, although there are exceptions when keys are deleted
30128  *   and reinstated. See the
30129  *   [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
30130  *
30131  * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
30132  *   it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
30133  *
30134  * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
30135  *   objects, and will throw an error if used with one.
30136  *
30137  * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
30138  * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
30139  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
30140  * or implement a `$watch` on the object yourself.
30141  *
30142  *
30143  * # Tracking and Duplicates
30144  *
30145  * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
30146  * the collection. When a change happens, `ngRepeat` then makes the corresponding changes to the DOM:
30147  *
30148  * * When an item is added, a new instance of the template is added to the DOM.
30149  * * When an item is removed, its template instance is removed from the DOM.
30150  * * When items are reordered, their respective templates are reordered in the DOM.
30151  *
30152  * To minimize creation of DOM elements, `ngRepeat` uses a function
30153  * to "keep track" of all items in the collection and their corresponding DOM elements.
30154  * For example, if an item is added to the collection, `ngRepeat` will know that all other items
30155  * already have DOM elements, and will not re-render them.
30156  *
30157  * The default tracking function (which tracks items by their identity) does not allow
30158  * duplicate items in arrays. This is because when there are duplicates, it is not possible
30159  * to maintain a one-to-one mapping between collection items and DOM elements.
30160  *
30161  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
30162  * with your own using the `track by` expression.
30163  *
30164  * For example, you may track items by the index of each item in the collection, using the
30165  * special scope property `$index`:
30166  * ```html
30167  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
30168  *      {{n}}
30169  *    </div>
30170  * ```
30171  *
30172  * You may also use arbitrary expressions in `track by`, including references to custom functions
30173  * on the scope:
30174  * ```html
30175  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
30176  *      {{n}}
30177  *    </div>
30178  * ```
30179  *
30180  * <div class="alert alert-success">
30181  * If you are working with objects that have a unique identifier property, you should track
30182  * by this identifier instead of the object instance. Should you reload your data later, `ngRepeat`
30183  * will not have to rebuild the DOM elements for items it has already rendered, even if the
30184  * JavaScript objects in the collection have been substituted for new ones. For large collections,
30185  * this significantly improves rendering performance. If you don't have a unique identifier,
30186  * `track by $index` can also provide a performance boost.
30187  * </div>
30188  *
30189  * ```html
30190  *    <div ng-repeat="model in collection track by model.id">
30191  *      {{model.name}}
30192  *    </div>
30193  * ```
30194  *
30195  * <br />
30196  * <div class="alert alert-warning">
30197  * Avoid using `track by $index` when the repeated template contains
30198  * {@link guide/expression#one-time-binding one-time bindings}. In such cases, the `nth` DOM
30199  * element will always be matched with the `nth` item of the array, so the bindings on that element
30200  * will not be updated even when the corresponding item changes, essentially causing the view to get
30201  * out-of-sync with the underlying data.
30202  * </div>
30203  *
30204  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
30205  * `$id` function, which tracks items by their identity:
30206  * ```html
30207  *    <div ng-repeat="obj in collection track by $id(obj)">
30208  *      {{obj.prop}}
30209  *    </div>
30210  * ```
30211  *
30212  * <br />
30213  * <div class="alert alert-warning">
30214  * **Note:** `track by` must always be the last expression:
30215  * </div>
30216  * ```
30217  *    <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
30218  *      {{model.name}}
30219  *    </div>
30220  * ```
30221  *
30222  *
30223  * # Special repeat start and end points
30224  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
30225  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
30226  * 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)
30227  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
30228  *
30229  * The example below makes use of this feature:
30230  * ```html
30231  *   <header ng-repeat-start="item in items">
30232  *     Header {{ item }}
30233  *   </header>
30234  *   <div class="body">
30235  *     Body {{ item }}
30236  *   </div>
30237  *   <footer ng-repeat-end>
30238  *     Footer {{ item }}
30239  *   </footer>
30240  * ```
30241  *
30242  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
30243  * ```html
30244  *   <header>
30245  *     Header A
30246  *   </header>
30247  *   <div class="body">
30248  *     Body A
30249  *   </div>
30250  *   <footer>
30251  *     Footer A
30252  *   </footer>
30253  *   <header>
30254  *     Header B
30255  *   </header>
30256  *   <div class="body">
30257  *     Body B
30258  *   </div>
30259  *   <footer>
30260  *     Footer B
30261  *   </footer>
30262  * ```
30263  *
30264  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
30265  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
30266  *
30267  * @animations
30268  * | Animation                        | Occurs                              |
30269  * |----------------------------------|-------------------------------------|
30270  * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
30271  * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
30272  * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
30273  *
30274  * See the example below for defining CSS animations with ngRepeat.
30275  *
30276  * @element ANY
30277  * @scope
30278  * @priority 1000
30279  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
30280  *   formats are currently supported:
30281  *
30282  *   * `variable in expression` â€“ where variable is the user defined loop variable and `expression`
30283  *     is a scope expression giving the collection to enumerate.
30284  *
30285  *     For example: `album in artist.albums`.
30286  *
30287  *   * `(key, value) in expression` â€“ where `key` and `value` can be any user defined identifiers,
30288  *     and `expression` is the scope expression giving the collection to enumerate.
30289  *
30290  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
30291  *
30292  *   * `variable in expression track by tracking_expression` â€“ You can also provide an optional tracking expression
30293  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
30294  *     is specified, ng-repeat associates elements by identity. It is an error to have
30295  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
30296  *     mapped to the same DOM element, which is not possible.)
30297  *
30298  *     Note that the tracking expression must come last, after any filters, and the alias expression.
30299  *
30300  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
30301  *     will be associated by item identity in the array.
30302  *
30303  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
30304  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
30305  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
30306  *     element in the same way in the DOM.
30307  *
30308  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
30309  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
30310  *     property is same.
30311  *
30312  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
30313  *     to items in conjunction with a tracking expression.
30314  *
30315  *   * `variable in expression as alias_expression` â€“ You can also provide an optional alias expression which will then store the
30316  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
30317  *     when a filter is active on the repeater, but the filtered result set is empty.
30318  *
30319  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
30320  *     the items have been processed through the filter.
30321  *
30322  *     Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax so it can be used only at the end
30323  *     (and not as operator, inside an expression).
30324  *
30325  *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
30326  *
30327  * @example
30328  * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
30329  * results by name or by age. New (entering) and removed (leaving) items are animated.
30330   <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true" name="ng-repeat">
30331     <file name="index.html">
30332       <div ng-controller="repeatController">
30333         I have {{friends.length}} friends. They are:
30334         <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
30335         <ul class="example-animate-container">
30336           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
30337             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
30338           </li>
30339           <li class="animate-repeat" ng-if="results.length === 0">
30340             <strong>No results found...</strong>
30341           </li>
30342         </ul>
30343       </div>
30344     </file>
30345     <file name="script.js">
30346       angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
30347         $scope.friends = [
30348           {name:'John', age:25, gender:'boy'},
30349           {name:'Jessie', age:30, gender:'girl'},
30350           {name:'Johanna', age:28, gender:'girl'},
30351           {name:'Joy', age:15, gender:'girl'},
30352           {name:'Mary', age:28, gender:'girl'},
30353           {name:'Peter', age:95, gender:'boy'},
30354           {name:'Sebastian', age:50, gender:'boy'},
30355           {name:'Erika', age:27, gender:'girl'},
30356           {name:'Patrick', age:40, gender:'boy'},
30357           {name:'Samantha', age:60, gender:'girl'}
30358         ];
30359       });
30360     </file>
30361     <file name="animations.css">
30362       .example-animate-container {
30363         background:white;
30364         border:1px solid black;
30365         list-style:none;
30366         margin:0;
30367         padding:0 10px;
30368       }
30369
30370       .animate-repeat {
30371         line-height:30px;
30372         list-style:none;
30373         box-sizing:border-box;
30374       }
30375
30376       .animate-repeat.ng-move,
30377       .animate-repeat.ng-enter,
30378       .animate-repeat.ng-leave {
30379         transition:all linear 0.5s;
30380       }
30381
30382       .animate-repeat.ng-leave.ng-leave-active,
30383       .animate-repeat.ng-move,
30384       .animate-repeat.ng-enter {
30385         opacity:0;
30386         max-height:0;
30387       }
30388
30389       .animate-repeat.ng-leave,
30390       .animate-repeat.ng-move.ng-move-active,
30391       .animate-repeat.ng-enter.ng-enter-active {
30392         opacity:1;
30393         max-height:30px;
30394       }
30395     </file>
30396     <file name="protractor.js" type="protractor">
30397       var friends = element.all(by.repeater('friend in friends'));
30398
30399       it('should render initial data set', function() {
30400         expect(friends.count()).toBe(10);
30401         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
30402         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
30403         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
30404         expect(element(by.binding('friends.length')).getText())
30405             .toMatch("I have 10 friends. They are:");
30406       });
30407
30408        it('should update repeater when filter predicate changes', function() {
30409          expect(friends.count()).toBe(10);
30410
30411          element(by.model('q')).sendKeys('ma');
30412
30413          expect(friends.count()).toBe(2);
30414          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
30415          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
30416        });
30417       </file>
30418     </example>
30419  */
30420 var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
30421   var NG_REMOVED = '$$NG_REMOVED';
30422   var ngRepeatMinErr = minErr('ngRepeat');
30423
30424   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
30425     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
30426     scope[valueIdentifier] = value;
30427     if (keyIdentifier) scope[keyIdentifier] = key;
30428     scope.$index = index;
30429     scope.$first = (index === 0);
30430     scope.$last = (index === (arrayLength - 1));
30431     scope.$middle = !(scope.$first || scope.$last);
30432     // eslint-disable-next-line no-bitwise
30433     scope.$odd = !(scope.$even = (index & 1) === 0);
30434   };
30435
30436   var getBlockStart = function(block) {
30437     return block.clone[0];
30438   };
30439
30440   var getBlockEnd = function(block) {
30441     return block.clone[block.clone.length - 1];
30442   };
30443
30444
30445   return {
30446     restrict: 'A',
30447     multiElement: true,
30448     transclude: 'element',
30449     priority: 1000,
30450     terminal: true,
30451     $$tlb: true,
30452     compile: function ngRepeatCompile($element, $attr) {
30453       var expression = $attr.ngRepeat;
30454       var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
30455
30456       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*$/);
30457
30458       if (!match) {
30459         throw ngRepeatMinErr('iexp', 'Expected expression in form of \'_item_ in _collection_[ track by _id_]\' but got \'{0}\'.',
30460             expression);
30461       }
30462
30463       var lhs = match[1];
30464       var rhs = match[2];
30465       var aliasAs = match[3];
30466       var trackByExp = match[4];
30467
30468       match = lhs.match(/^(?:(\s*[$\w]+)|\(\s*([$\w]+)\s*,\s*([$\w]+)\s*\))$/);
30469
30470       if (!match) {
30471         throw ngRepeatMinErr('iidexp', '\'_item_\' in \'_item_ in _collection_\' should be an identifier or \'(_key_, _value_)\' expression, but got \'{0}\'.',
30472             lhs);
30473       }
30474       var valueIdentifier = match[3] || match[1];
30475       var keyIdentifier = match[2];
30476
30477       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
30478           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
30479         throw ngRepeatMinErr('badident', 'alias \'{0}\' is invalid --- must be a valid JS identifier which is not a reserved name.',
30480           aliasAs);
30481       }
30482
30483       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
30484       var hashFnLocals = {$id: hashKey};
30485
30486       if (trackByExp) {
30487         trackByExpGetter = $parse(trackByExp);
30488       } else {
30489         trackByIdArrayFn = function(key, value) {
30490           return hashKey(value);
30491         };
30492         trackByIdObjFn = function(key) {
30493           return key;
30494         };
30495       }
30496
30497       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
30498
30499         if (trackByExpGetter) {
30500           trackByIdExpFn = function(key, value, index) {
30501             // assign key, value, and $index to the locals so that they can be used in hash functions
30502             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
30503             hashFnLocals[valueIdentifier] = value;
30504             hashFnLocals.$index = index;
30505             return trackByExpGetter($scope, hashFnLocals);
30506           };
30507         }
30508
30509         // Store a list of elements from previous run. This is a hash where key is the item from the
30510         // iterator, and the value is objects with following properties.
30511         //   - scope: bound scope
30512         //   - element: previous element.
30513         //   - index: position
30514         //
30515         // We are using no-proto object so that we don't need to guard against inherited props via
30516         // hasOwnProperty.
30517         var lastBlockMap = createMap();
30518
30519         //watch props
30520         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
30521           var index, length,
30522               previousNode = $element[0],     // node that cloned nodes should be inserted after
30523                                               // initialized to the comment node anchor
30524               nextNode,
30525               // Same as lastBlockMap but it has the current state. It will become the
30526               // lastBlockMap on the next iteration.
30527               nextBlockMap = createMap(),
30528               collectionLength,
30529               key, value, // key/value of iteration
30530               trackById,
30531               trackByIdFn,
30532               collectionKeys,
30533               block,       // last object information {scope, element, id}
30534               nextBlockOrder,
30535               elementsToRemove;
30536
30537           if (aliasAs) {
30538             $scope[aliasAs] = collection;
30539           }
30540
30541           if (isArrayLike(collection)) {
30542             collectionKeys = collection;
30543             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
30544           } else {
30545             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
30546             // if object, extract keys, in enumeration order, unsorted
30547             collectionKeys = [];
30548             for (var itemKey in collection) {
30549               if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
30550                 collectionKeys.push(itemKey);
30551               }
30552             }
30553           }
30554
30555           collectionLength = collectionKeys.length;
30556           nextBlockOrder = new Array(collectionLength);
30557
30558           // locate existing items
30559           for (index = 0; index < collectionLength; index++) {
30560             key = (collection === collectionKeys) ? index : collectionKeys[index];
30561             value = collection[key];
30562             trackById = trackByIdFn(key, value, index);
30563             if (lastBlockMap[trackById]) {
30564               // found previously seen block
30565               block = lastBlockMap[trackById];
30566               delete lastBlockMap[trackById];
30567               nextBlockMap[trackById] = block;
30568               nextBlockOrder[index] = block;
30569             } else if (nextBlockMap[trackById]) {
30570               // if collision detected. restore lastBlockMap and throw an error
30571               forEach(nextBlockOrder, function(block) {
30572                 if (block && block.scope) lastBlockMap[block.id] = block;
30573               });
30574               throw ngRepeatMinErr('dupes',
30575                   'Duplicates in a repeater are not allowed. Use \'track by\' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}',
30576                   expression, trackById, value);
30577             } else {
30578               // new never before seen block
30579               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
30580               nextBlockMap[trackById] = true;
30581             }
30582           }
30583
30584           // remove leftover items
30585           for (var blockKey in lastBlockMap) {
30586             block = lastBlockMap[blockKey];
30587             elementsToRemove = getBlockNodes(block.clone);
30588             $animate.leave(elementsToRemove);
30589             if (elementsToRemove[0].parentNode) {
30590               // if the element was not removed yet because of pending animation, mark it as deleted
30591               // so that we can ignore it later
30592               for (index = 0, length = elementsToRemove.length; index < length; index++) {
30593                 elementsToRemove[index][NG_REMOVED] = true;
30594               }
30595             }
30596             block.scope.$destroy();
30597           }
30598
30599           // we are not using forEach for perf reasons (trying to avoid #call)
30600           for (index = 0; index < collectionLength; index++) {
30601             key = (collection === collectionKeys) ? index : collectionKeys[index];
30602             value = collection[key];
30603             block = nextBlockOrder[index];
30604
30605             if (block.scope) {
30606               // if we have already seen this object, then we need to reuse the
30607               // associated scope/element
30608
30609               nextNode = previousNode;
30610
30611               // skip nodes that are already pending removal via leave animation
30612               do {
30613                 nextNode = nextNode.nextSibling;
30614               } while (nextNode && nextNode[NG_REMOVED]);
30615
30616               if (getBlockStart(block) !== nextNode) {
30617                 // existing item which got moved
30618                 $animate.move(getBlockNodes(block.clone), null, previousNode);
30619               }
30620               previousNode = getBlockEnd(block);
30621               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
30622             } else {
30623               // new item which we don't know about
30624               $transclude(function ngRepeatTransclude(clone, scope) {
30625                 block.scope = scope;
30626                 // http://jsperf.com/clone-vs-createcomment
30627                 var endNode = ngRepeatEndComment.cloneNode(false);
30628                 clone[clone.length++] = endNode;
30629
30630                 $animate.enter(clone, null, previousNode);
30631                 previousNode = endNode;
30632                 // Note: We only need the first/last node of the cloned nodes.
30633                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
30634                 // by a directive with templateUrl when its template arrives.
30635                 block.clone = clone;
30636                 nextBlockMap[block.id] = block;
30637                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
30638               });
30639             }
30640           }
30641           lastBlockMap = nextBlockMap;
30642         });
30643       };
30644     }
30645   };
30646 }];
30647
30648 var NG_HIDE_CLASS = 'ng-hide';
30649 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
30650 /**
30651  * @ngdoc directive
30652  * @name ngShow
30653  * @multiElement
30654  *
30655  * @description
30656  * The `ngShow` directive shows or hides the given HTML element based on the expression
30657  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
30658  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
30659  * in AngularJS and sets the display style to none (using an !important flag).
30660  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
30661  *
30662  * ```html
30663  * <!-- when $scope.myValue is truthy (element is visible) -->
30664  * <div ng-show="myValue"></div>
30665  *
30666  * <!-- when $scope.myValue is falsy (element is hidden) -->
30667  * <div ng-show="myValue" class="ng-hide"></div>
30668  * ```
30669  *
30670  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
30671  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
30672  * from the element causing the element not to appear hidden.
30673  *
30674  * ## Why is !important used?
30675  *
30676  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
30677  * can be easily overridden by heavier selectors. For example, something as simple
30678  * as changing the display style on a HTML list item would make hidden elements appear visible.
30679  * This also becomes a bigger issue when dealing with CSS frameworks.
30680  *
30681  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
30682  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
30683  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
30684  *
30685  * ### Overriding `.ng-hide`
30686  *
30687  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
30688  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
30689  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
30690  * with extra animation classes that can be added.
30691  *
30692  * ```css
30693  * .ng-hide:not(.ng-hide-animate) {
30694  *   /&#42; this is just another form of hiding an element &#42;/
30695  *   display: block!important;
30696  *   position: absolute;
30697  *   top: -9999px;
30698  *   left: -9999px;
30699  * }
30700  * ```
30701  *
30702  * By default you don't need to override in CSS anything and the animations will work around the display style.
30703  *
30704  * ## A note about animations with `ngShow`
30705  *
30706  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
30707  * is true and false. This system works like the animation system present with ngClass except that
30708  * you must also include the !important flag to override the display property
30709  * so that you can perform an animation when the element is hidden during the time of the animation.
30710  *
30711  * ```css
30712  * //
30713  * //a working example can be found at the bottom of this page
30714  * //
30715  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
30716  *   /&#42; this is required as of 1.3x to properly
30717  *      apply all styling in a show/hide animation &#42;/
30718  *   transition: 0s linear all;
30719  * }
30720  *
30721  * .my-element.ng-hide-add-active,
30722  * .my-element.ng-hide-remove-active {
30723  *   /&#42; the transition is defined in the active class &#42;/
30724  *   transition: 1s linear all;
30725  * }
30726  *
30727  * .my-element.ng-hide-add { ... }
30728  * .my-element.ng-hide-add.ng-hide-add-active { ... }
30729  * .my-element.ng-hide-remove { ... }
30730  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
30731  * ```
30732  *
30733  * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
30734  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
30735  *
30736  * @animations
30737  * | Animation                        | Occurs                              |
30738  * |----------------------------------|-------------------------------------|
30739  * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden |
30740  * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |
30741  *
30742  * @element ANY
30743  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
30744  *     then the element is shown or hidden respectively.
30745  *
30746  * @example
30747   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-show">
30748     <file name="index.html">
30749       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
30750       <div>
30751         Show:
30752         <div class="check-element animate-show" ng-show="checked">
30753           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
30754         </div>
30755       </div>
30756       <div>
30757         Hide:
30758         <div class="check-element animate-show" ng-hide="checked">
30759           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
30760         </div>
30761       </div>
30762     </file>
30763     <file name="glyphicons.css">
30764       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
30765     </file>
30766     <file name="animations.css">
30767       .animate-show {
30768         line-height: 20px;
30769         opacity: 1;
30770         padding: 10px;
30771         border: 1px solid black;
30772         background: white;
30773       }
30774
30775       .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
30776         transition: all linear 0.5s;
30777       }
30778
30779       .animate-show.ng-hide {
30780         line-height: 0;
30781         opacity: 0;
30782         padding: 0 10px;
30783       }
30784
30785       .check-element {
30786         padding: 10px;
30787         border: 1px solid black;
30788         background: white;
30789       }
30790     </file>
30791     <file name="protractor.js" type="protractor">
30792       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
30793       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
30794
30795       it('should check ng-show / ng-hide', function() {
30796         expect(thumbsUp.isDisplayed()).toBeFalsy();
30797         expect(thumbsDown.isDisplayed()).toBeTruthy();
30798
30799         element(by.model('checked')).click();
30800
30801         expect(thumbsUp.isDisplayed()).toBeTruthy();
30802         expect(thumbsDown.isDisplayed()).toBeFalsy();
30803       });
30804     </file>
30805   </example>
30806  */
30807 var ngShowDirective = ['$animate', function($animate) {
30808   return {
30809     restrict: 'A',
30810     multiElement: true,
30811     link: function(scope, element, attr) {
30812       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
30813         // we're adding a temporary, animation-specific class for ng-hide since this way
30814         // we can control when the element is actually displayed on screen without having
30815         // to have a global/greedy CSS selector that breaks when other animations are run.
30816         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
30817         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
30818           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
30819         });
30820       });
30821     }
30822   };
30823 }];
30824
30825
30826 /**
30827  * @ngdoc directive
30828  * @name ngHide
30829  * @multiElement
30830  *
30831  * @description
30832  * The `ngHide` directive shows or hides the given HTML element based on the expression
30833  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
30834  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
30835  * in AngularJS and sets the display style to none (using an !important flag).
30836  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
30837  *
30838  * ```html
30839  * <!-- when $scope.myValue is truthy (element is hidden) -->
30840  * <div ng-hide="myValue" class="ng-hide"></div>
30841  *
30842  * <!-- when $scope.myValue is falsy (element is visible) -->
30843  * <div ng-hide="myValue"></div>
30844  * ```
30845  *
30846  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
30847  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
30848  * from the element causing the element not to appear hidden.
30849  *
30850  * ## Why is !important used?
30851  *
30852  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
30853  * can be easily overridden by heavier selectors. For example, something as simple
30854  * as changing the display style on a HTML list item would make hidden elements appear visible.
30855  * This also becomes a bigger issue when dealing with CSS frameworks.
30856  *
30857  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
30858  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
30859  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
30860  *
30861  * ### Overriding `.ng-hide`
30862  *
30863  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
30864  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
30865  * class in CSS:
30866  *
30867  * ```css
30868  * .ng-hide {
30869  *   /&#42; this is just another form of hiding an element &#42;/
30870  *   display: block!important;
30871  *   position: absolute;
30872  *   top: -9999px;
30873  *   left: -9999px;
30874  * }
30875  * ```
30876  *
30877  * By default you don't need to override in CSS anything and the animations will work around the display style.
30878  *
30879  * ## A note about animations with `ngHide`
30880  *
30881  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
30882  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
30883  * CSS class is added and removed for you instead of your own CSS class.
30884  *
30885  * ```css
30886  * //
30887  * //a working example can be found at the bottom of this page
30888  * //
30889  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
30890  *   transition: 0.5s linear all;
30891  * }
30892  *
30893  * .my-element.ng-hide-add { ... }
30894  * .my-element.ng-hide-add.ng-hide-add-active { ... }
30895  * .my-element.ng-hide-remove { ... }
30896  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
30897  * ```
30898  *
30899  * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
30900  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
30901  *
30902  * @animations
30903  * | Animation                        | Occurs                              |
30904  * |----------------------------------|-------------------------------------|
30905  * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |
30906  * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |
30907  *
30908  *
30909  * @element ANY
30910  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
30911  *     the element is shown or hidden respectively.
30912  *
30913  * @example
30914   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-hide">
30915     <file name="index.html">
30916       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
30917       <div>
30918         Show:
30919         <div class="check-element animate-hide" ng-show="checked">
30920           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
30921         </div>
30922       </div>
30923       <div>
30924         Hide:
30925         <div class="check-element animate-hide" ng-hide="checked">
30926           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
30927         </div>
30928       </div>
30929     </file>
30930     <file name="glyphicons.css">
30931       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
30932     </file>
30933     <file name="animations.css">
30934       .animate-hide {
30935         transition: all linear 0.5s;
30936         line-height: 20px;
30937         opacity: 1;
30938         padding: 10px;
30939         border: 1px solid black;
30940         background: white;
30941       }
30942
30943       .animate-hide.ng-hide {
30944         line-height: 0;
30945         opacity: 0;
30946         padding: 0 10px;
30947       }
30948
30949       .check-element {
30950         padding: 10px;
30951         border: 1px solid black;
30952         background: white;
30953       }
30954     </file>
30955     <file name="protractor.js" type="protractor">
30956       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
30957       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
30958
30959       it('should check ng-show / ng-hide', function() {
30960         expect(thumbsUp.isDisplayed()).toBeFalsy();
30961         expect(thumbsDown.isDisplayed()).toBeTruthy();
30962
30963         element(by.model('checked')).click();
30964
30965         expect(thumbsUp.isDisplayed()).toBeTruthy();
30966         expect(thumbsDown.isDisplayed()).toBeFalsy();
30967       });
30968     </file>
30969   </example>
30970  */
30971 var ngHideDirective = ['$animate', function($animate) {
30972   return {
30973     restrict: 'A',
30974     multiElement: true,
30975     link: function(scope, element, attr) {
30976       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
30977         // The comment inside of the ngShowDirective explains why we add and
30978         // remove a temporary class for the show/hide animation
30979         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
30980           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
30981         });
30982       });
30983     }
30984   };
30985 }];
30986
30987 /**
30988  * @ngdoc directive
30989  * @name ngStyle
30990  * @restrict AC
30991  *
30992  * @description
30993  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
30994  *
30995  * @knownIssue
30996  * You should not use {@link guide/interpolation interpolation} in the value of the `style`
30997  * attribute, when using the `ngStyle` directive on the same element.
30998  * See {@link guide/interpolation#known-issues here} for more info.
30999  *
31000  * @element ANY
31001  * @param {expression} ngStyle
31002  *
31003  * {@link guide/expression Expression} which evals to an
31004  * object whose keys are CSS style names and values are corresponding values for those CSS
31005  * keys.
31006  *
31007  * Since some CSS style names are not valid keys for an object, they must be quoted.
31008  * See the 'background-color' style in the example below.
31009  *
31010  * @example
31011    <example name="ng-style">
31012      <file name="index.html">
31013         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
31014         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
31015         <input type="button" value="clear" ng-click="myStyle={}">
31016         <br/>
31017         <span ng-style="myStyle">Sample Text</span>
31018         <pre>myStyle={{myStyle}}</pre>
31019      </file>
31020      <file name="style.css">
31021        span {
31022          color: black;
31023        }
31024      </file>
31025      <file name="protractor.js" type="protractor">
31026        var colorSpan = element(by.css('span'));
31027
31028        it('should check ng-style', function() {
31029          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
31030          element(by.css('input[value=\'set color\']')).click();
31031          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
31032          element(by.css('input[value=clear]')).click();
31033          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
31034        });
31035      </file>
31036    </example>
31037  */
31038 var ngStyleDirective = ngDirective(function(scope, element, attr) {
31039   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
31040     if (oldStyles && (newStyles !== oldStyles)) {
31041       forEach(oldStyles, function(val, style) { element.css(style, '');});
31042     }
31043     if (newStyles) element.css(newStyles);
31044   }, true);
31045 });
31046
31047 /**
31048  * @ngdoc directive
31049  * @name ngSwitch
31050  * @restrict EA
31051  *
31052  * @description
31053  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
31054  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
31055  * as specified in the template.
31056  *
31057  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
31058  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
31059  * matches the value obtained from the evaluated expression. In other words, you define a container element
31060  * (where you place the directive), place an expression on the **`on="..."` attribute**
31061  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
31062  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
31063  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
31064  * attribute is displayed.
31065  *
31066  * <div class="alert alert-info">
31067  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
31068  * as literal string values to match against.
31069  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
31070  * value of the expression `$scope.someVal`.
31071  * </div>
31072
31073  * @animations
31074  * | Animation                        | Occurs                              |
31075  * |----------------------------------|-------------------------------------|
31076  * | {@link ng.$animate#enter enter}  | after the ngSwitch contents change and the matched child element is placed inside the container |
31077  * | {@link ng.$animate#leave leave}  | after the ngSwitch contents change and just before the former contents are removed from the DOM |
31078  *
31079  * @usage
31080  *
31081  * ```
31082  * <ANY ng-switch="expression">
31083  *   <ANY ng-switch-when="matchValue1">...</ANY>
31084  *   <ANY ng-switch-when="matchValue2">...</ANY>
31085  *   <ANY ng-switch-default>...</ANY>
31086  * </ANY>
31087  * ```
31088  *
31089  *
31090  * @scope
31091  * @priority 1200
31092  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
31093  * On child elements add:
31094  *
31095  * * `ngSwitchWhen`: the case statement to match against. If match then this
31096  *   case will be displayed. If the same match appears multiple times, all the
31097  *   elements will be displayed. It is possible to associate multiple values to
31098  *   the same `ngSwitchWhen` by defining the optional attribute
31099  *   `ngSwitchWhenSeparator`. The separator will be used to split the value of
31100  *   the `ngSwitchWhen` attribute into multiple tokens, and the element will show
31101  *   if any of the `ngSwitch` evaluates to any of these tokens.
31102  * * `ngSwitchDefault`: the default case when no other case match. If there
31103  *   are multiple default cases, all of them will be displayed when no other
31104  *   case match.
31105  *
31106  *
31107  * @example
31108   <example module="switchExample" deps="angular-animate.js" animations="true" name="ng-switch">
31109     <file name="index.html">
31110       <div ng-controller="ExampleController">
31111         <select ng-model="selection" ng-options="item for item in items">
31112         </select>
31113         <code>selection={{selection}}</code>
31114         <hr/>
31115         <div class="animate-switch-container"
31116           ng-switch on="selection">
31117             <div class="animate-switch" ng-switch-when="settings|options" ng-switch-when-separator="|">Settings Div</div>
31118             <div class="animate-switch" ng-switch-when="home">Home Span</div>
31119             <div class="animate-switch" ng-switch-default>default</div>
31120         </div>
31121       </div>
31122     </file>
31123     <file name="script.js">
31124       angular.module('switchExample', ['ngAnimate'])
31125         .controller('ExampleController', ['$scope', function($scope) {
31126           $scope.items = ['settings', 'home', 'options', 'other'];
31127           $scope.selection = $scope.items[0];
31128         }]);
31129     </file>
31130     <file name="animations.css">
31131       .animate-switch-container {
31132         position:relative;
31133         background:white;
31134         border:1px solid black;
31135         height:40px;
31136         overflow:hidden;
31137       }
31138
31139       .animate-switch {
31140         padding:10px;
31141       }
31142
31143       .animate-switch.ng-animate {
31144         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
31145
31146         position:absolute;
31147         top:0;
31148         left:0;
31149         right:0;
31150         bottom:0;
31151       }
31152
31153       .animate-switch.ng-leave.ng-leave-active,
31154       .animate-switch.ng-enter {
31155         top:-50px;
31156       }
31157       .animate-switch.ng-leave,
31158       .animate-switch.ng-enter.ng-enter-active {
31159         top:0;
31160       }
31161     </file>
31162     <file name="protractor.js" type="protractor">
31163       var switchElem = element(by.css('[ng-switch]'));
31164       var select = element(by.model('selection'));
31165
31166       it('should start in settings', function() {
31167         expect(switchElem.getText()).toMatch(/Settings Div/);
31168       });
31169       it('should change to home', function() {
31170         select.all(by.css('option')).get(1).click();
31171         expect(switchElem.getText()).toMatch(/Home Span/);
31172       });
31173       it('should change to settings via "options"', function() {
31174         select.all(by.css('option')).get(2).click();
31175         expect(switchElem.getText()).toMatch(/Settings Div/);
31176       });
31177       it('should select default', function() {
31178         select.all(by.css('option')).get(3).click();
31179         expect(switchElem.getText()).toMatch(/default/);
31180       });
31181     </file>
31182   </example>
31183  */
31184 var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
31185   return {
31186     require: 'ngSwitch',
31187
31188     // asks for $scope to fool the BC controller module
31189     controller: ['$scope', function NgSwitchController() {
31190      this.cases = {};
31191     }],
31192     link: function(scope, element, attr, ngSwitchController) {
31193       var watchExpr = attr.ngSwitch || attr.on,
31194           selectedTranscludes = [],
31195           selectedElements = [],
31196           previousLeaveAnimations = [],
31197           selectedScopes = [];
31198
31199       var spliceFactory = function(array, index) {
31200           return function(response) {
31201             if (response !== false) array.splice(index, 1);
31202           };
31203       };
31204
31205       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
31206         var i, ii;
31207
31208         // Start with the last, in case the array is modified during the loop
31209         while (previousLeaveAnimations.length) {
31210           $animate.cancel(previousLeaveAnimations.pop());
31211         }
31212
31213         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
31214           var selected = getBlockNodes(selectedElements[i].clone);
31215           selectedScopes[i].$destroy();
31216           var runner = previousLeaveAnimations[i] = $animate.leave(selected);
31217           runner.done(spliceFactory(previousLeaveAnimations, i));
31218         }
31219
31220         selectedElements.length = 0;
31221         selectedScopes.length = 0;
31222
31223         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
31224           forEach(selectedTranscludes, function(selectedTransclude) {
31225             selectedTransclude.transclude(function(caseElement, selectedScope) {
31226               selectedScopes.push(selectedScope);
31227               var anchor = selectedTransclude.element;
31228               caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
31229               var block = { clone: caseElement };
31230
31231               selectedElements.push(block);
31232               $animate.enter(caseElement, anchor.parent(), anchor);
31233             });
31234           });
31235         }
31236       });
31237     }
31238   };
31239 }];
31240
31241 var ngSwitchWhenDirective = ngDirective({
31242   transclude: 'element',
31243   priority: 1200,
31244   require: '^ngSwitch',
31245   multiElement: true,
31246   link: function(scope, element, attrs, ctrl, $transclude) {
31247
31248     var cases = attrs.ngSwitchWhen.split(attrs.ngSwitchWhenSeparator).sort().filter(
31249       // Filter duplicate cases
31250       function(element, index, array) { return array[index - 1] !== element; }
31251     );
31252
31253     forEach(cases, function(whenCase) {
31254       ctrl.cases['!' + whenCase] = (ctrl.cases['!' + whenCase] || []);
31255       ctrl.cases['!' + whenCase].push({ transclude: $transclude, element: element });
31256     });
31257   }
31258 });
31259
31260 var ngSwitchDefaultDirective = ngDirective({
31261   transclude: 'element',
31262   priority: 1200,
31263   require: '^ngSwitch',
31264   multiElement: true,
31265   link: function(scope, element, attr, ctrl, $transclude) {
31266     ctrl.cases['?'] = (ctrl.cases['?'] || []);
31267     ctrl.cases['?'].push({ transclude: $transclude, element: element });
31268    }
31269 });
31270
31271 /**
31272  * @ngdoc directive
31273  * @name ngTransclude
31274  * @restrict EAC
31275  *
31276  * @description
31277  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
31278  *
31279  * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
31280  * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
31281  *
31282  * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
31283  * content of this element will be removed before the transcluded content is inserted.
31284  * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
31285  * that no transcluded content is provided.
31286  *
31287  * @element ANY
31288  *
31289  * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
31290  *                                               or its value is the same as the name of the attribute then the default slot is used.
31291  *
31292  * @example
31293  * ### Basic transclusion
31294  * This example demonstrates basic transclusion of content into a component directive.
31295  * <example name="simpleTranscludeExample" module="transcludeExample">
31296  *   <file name="index.html">
31297  *     <script>
31298  *       angular.module('transcludeExample', [])
31299  *        .directive('pane', function(){
31300  *           return {
31301  *             restrict: 'E',
31302  *             transclude: true,
31303  *             scope: { title:'@' },
31304  *             template: '<div style="border: 1px solid black;">' +
31305  *                         '<div style="background-color: gray">{{title}}</div>' +
31306  *                         '<ng-transclude></ng-transclude>' +
31307  *                       '</div>'
31308  *           };
31309  *       })
31310  *       .controller('ExampleController', ['$scope', function($scope) {
31311  *         $scope.title = 'Lorem Ipsum';
31312  *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
31313  *       }]);
31314  *     </script>
31315  *     <div ng-controller="ExampleController">
31316  *       <input ng-model="title" aria-label="title"> <br/>
31317  *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
31318  *       <pane title="{{title}}">{{text}}</pane>
31319  *     </div>
31320  *   </file>
31321  *   <file name="protractor.js" type="protractor">
31322  *      it('should have transcluded', function() {
31323  *        var titleElement = element(by.model('title'));
31324  *        titleElement.clear();
31325  *        titleElement.sendKeys('TITLE');
31326  *        var textElement = element(by.model('text'));
31327  *        textElement.clear();
31328  *        textElement.sendKeys('TEXT');
31329  *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
31330  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
31331  *      });
31332  *   </file>
31333  * </example>
31334  *
31335  * @example
31336  * ### Transclude fallback content
31337  * This example shows how to use `NgTransclude` with fallback content, that
31338  * is displayed if no transcluded content is provided.
31339  *
31340  * <example module="transcludeFallbackContentExample" name="ng-transclude">
31341  * <file name="index.html">
31342  * <script>
31343  * angular.module('transcludeFallbackContentExample', [])
31344  * .directive('myButton', function(){
31345  *             return {
31346  *               restrict: 'E',
31347  *               transclude: true,
31348  *               scope: true,
31349  *               template: '<button style="cursor: pointer;">' +
31350  *                           '<ng-transclude>' +
31351  *                             '<b style="color: red;">Button1</b>' +
31352  *                           '</ng-transclude>' +
31353  *                         '</button>'
31354  *             };
31355  *         });
31356  * </script>
31357  * <!-- fallback button content -->
31358  * <my-button id="fallback"></my-button>
31359  * <!-- modified button content -->
31360  * <my-button id="modified">
31361  *   <i style="color: green;">Button2</i>
31362  * </my-button>
31363  * </file>
31364  * <file name="protractor.js" type="protractor">
31365  * it('should have different transclude element content', function() {
31366  *          expect(element(by.id('fallback')).getText()).toBe('Button1');
31367  *          expect(element(by.id('modified')).getText()).toBe('Button2');
31368  *        });
31369  * </file>
31370  * </example>
31371  *
31372  * @example
31373  * ### Multi-slot transclusion
31374  * This example demonstrates using multi-slot transclusion in a component directive.
31375  * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
31376  *   <file name="index.html">
31377  *    <style>
31378  *      .title, .footer {
31379  *        background-color: gray
31380  *      }
31381  *    </style>
31382  *    <div ng-controller="ExampleController">
31383  *      <input ng-model="title" aria-label="title"> <br/>
31384  *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
31385  *      <pane>
31386  *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
31387  *        <pane-body><p>{{text}}</p></pane-body>
31388  *      </pane>
31389  *    </div>
31390  *   </file>
31391  *   <file name="app.js">
31392  *    angular.module('multiSlotTranscludeExample', [])
31393  *     .directive('pane', function() {
31394  *        return {
31395  *          restrict: 'E',
31396  *          transclude: {
31397  *            'title': '?paneTitle',
31398  *            'body': 'paneBody',
31399  *            'footer': '?paneFooter'
31400  *          },
31401  *          template: '<div style="border: 1px solid black;">' +
31402  *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
31403  *                      '<div ng-transclude="body"></div>' +
31404  *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
31405  *                    '</div>'
31406  *        };
31407  *    })
31408  *    .controller('ExampleController', ['$scope', function($scope) {
31409  *      $scope.title = 'Lorem Ipsum';
31410  *      $scope.link = 'https://google.com';
31411  *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
31412  *    }]);
31413  *   </file>
31414  *   <file name="protractor.js" type="protractor">
31415  *      it('should have transcluded the title and the body', function() {
31416  *        var titleElement = element(by.model('title'));
31417  *        titleElement.clear();
31418  *        titleElement.sendKeys('TITLE');
31419  *        var textElement = element(by.model('text'));
31420  *        textElement.clear();
31421  *        textElement.sendKeys('TEXT');
31422  *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
31423  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
31424  *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
31425  *      });
31426  *   </file>
31427  * </example>
31428  */
31429 var ngTranscludeMinErr = minErr('ngTransclude');
31430 var ngTranscludeDirective = ['$compile', function($compile) {
31431   return {
31432     restrict: 'EAC',
31433     terminal: true,
31434     compile: function ngTranscludeCompile(tElement) {
31435
31436       // Remove and cache any original content to act as a fallback
31437       var fallbackLinkFn = $compile(tElement.contents());
31438       tElement.empty();
31439
31440       return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {
31441
31442         if (!$transclude) {
31443           throw ngTranscludeMinErr('orphan',
31444           'Illegal use of ngTransclude directive in the template! ' +
31445           'No parent directive that requires a transclusion found. ' +
31446           'Element: {0}',
31447           startingTag($element));
31448         }
31449
31450
31451         // If the attribute is of the form: `ng-transclude="ng-transclude"` then treat it like the default
31452         if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
31453           $attrs.ngTransclude = '';
31454         }
31455         var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
31456
31457         // If the slot is required and no transclusion content is provided then this call will throw an error
31458         $transclude(ngTranscludeCloneAttachFn, null, slotName);
31459
31460         // If the slot is optional and no transclusion content is provided then use the fallback content
31461         if (slotName && !$transclude.isSlotFilled(slotName)) {
31462           useFallbackContent();
31463         }
31464
31465         function ngTranscludeCloneAttachFn(clone, transcludedScope) {
31466           if (clone.length) {
31467             $element.append(clone);
31468           } else {
31469             useFallbackContent();
31470             // There is nothing linked against the transcluded scope since no content was available,
31471             // so it should be safe to clean up the generated scope.
31472             transcludedScope.$destroy();
31473           }
31474         }
31475
31476         function useFallbackContent() {
31477           // Since this is the fallback content rather than the transcluded content,
31478           // we link against the scope of this directive rather than the transcluded scope
31479           fallbackLinkFn($scope, function(clone) {
31480             $element.append(clone);
31481           });
31482         }
31483       };
31484     }
31485   };
31486 }];
31487
31488 /**
31489  * @ngdoc directive
31490  * @name script
31491  * @restrict E
31492  *
31493  * @description
31494  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
31495  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
31496  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
31497  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
31498  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
31499  *
31500  * @param {string} type Must be set to `'text/ng-template'`.
31501  * @param {string} id Cache name of the template.
31502  *
31503  * @example
31504   <example  name="script-tag">
31505     <file name="index.html">
31506       <script type="text/ng-template" id="/tpl.html">
31507         Content of the template.
31508       </script>
31509
31510       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
31511       <div id="tpl-content" ng-include src="currentTpl"></div>
31512     </file>
31513     <file name="protractor.js" type="protractor">
31514       it('should load template defined inside script tag', function() {
31515         element(by.css('#tpl-link')).click();
31516         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
31517       });
31518     </file>
31519   </example>
31520  */
31521 var scriptDirective = ['$templateCache', function($templateCache) {
31522   return {
31523     restrict: 'E',
31524     terminal: true,
31525     compile: function(element, attr) {
31526       if (attr.type === 'text/ng-template') {
31527         var templateUrl = attr.id,
31528             text = element[0].text;
31529
31530         $templateCache.put(templateUrl, text);
31531       }
31532     }
31533   };
31534 }];
31535
31536 /* exported selectDirective, optionDirective */
31537
31538 var noopNgModelController = { $setViewValue: noop, $render: noop };
31539
31540 function chromeHack(optionElement) {
31541   // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
31542   // Adding an <option selected="selected"> element to a <select required="required"> should
31543   // automatically select the new element
31544   if (optionElement[0].hasAttribute('selected')) {
31545     optionElement[0].selected = true;
31546   }
31547 }
31548
31549 /**
31550  * @ngdoc type
31551  * @name  select.SelectController
31552  * @description
31553  * The controller for the `<select>` directive. This provides support for reading
31554  * and writing the selected value(s) of the control and also coordinates dynamically
31555  * added `<option>` elements, perhaps by an `ngRepeat` directive.
31556  */
31557 var SelectController =
31558         ['$element', '$scope', /** @this */ function($element, $scope) {
31559
31560   var self = this,
31561       optionsMap = new HashMap();
31562
31563   // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
31564   self.ngModelCtrl = noopNgModelController;
31565
31566   // The "unknown" option is one that is prepended to the list if the viewValue
31567   // does not match any of the options. When it is rendered the value of the unknown
31568   // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
31569   //
31570   // We can't just jqLite('<option>') since jqLite is not smart enough
31571   // to create it in <select> and IE barfs otherwise.
31572   self.unknownOption = jqLite(window.document.createElement('option'));
31573   self.renderUnknownOption = function(val) {
31574     var unknownVal = '? ' + hashKey(val) + ' ?';
31575     self.unknownOption.val(unknownVal);
31576     $element.prepend(self.unknownOption);
31577     $element.val(unknownVal);
31578   };
31579
31580   $scope.$on('$destroy', function() {
31581     // disable unknown option so that we don't do work when the whole select is being destroyed
31582     self.renderUnknownOption = noop;
31583   });
31584
31585   self.removeUnknownOption = function() {
31586     if (self.unknownOption.parent()) self.unknownOption.remove();
31587   };
31588
31589
31590   // Read the value of the select control, the implementation of this changes depending
31591   // upon whether the select can have multiple values and whether ngOptions is at work.
31592   self.readValue = function readSingleValue() {
31593     self.removeUnknownOption();
31594     return $element.val();
31595   };
31596
31597
31598   // Write the value to the select control, the implementation of this changes depending
31599   // upon whether the select can have multiple values and whether ngOptions is at work.
31600   self.writeValue = function writeSingleValue(value) {
31601     if (self.hasOption(value)) {
31602       self.removeUnknownOption();
31603       $element.val(value);
31604       if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
31605     } else {
31606       if (value == null && self.emptyOption) {
31607         self.removeUnknownOption();
31608         $element.val('');
31609       } else {
31610         self.renderUnknownOption(value);
31611       }
31612     }
31613   };
31614
31615
31616   // Tell the select control that an option, with the given value, has been added
31617   self.addOption = function(value, element) {
31618     // Skip comment nodes, as they only pollute the `optionsMap`
31619     if (element[0].nodeType === NODE_TYPE_COMMENT) return;
31620
31621     assertNotHasOwnProperty(value, '"option value"');
31622     if (value === '') {
31623       self.emptyOption = element;
31624     }
31625     var count = optionsMap.get(value) || 0;
31626     optionsMap.put(value, count + 1);
31627     self.ngModelCtrl.$render();
31628     chromeHack(element);
31629   };
31630
31631   // Tell the select control that an option, with the given value, has been removed
31632   self.removeOption = function(value) {
31633     var count = optionsMap.get(value);
31634     if (count) {
31635       if (count === 1) {
31636         optionsMap.remove(value);
31637         if (value === '') {
31638           self.emptyOption = undefined;
31639         }
31640       } else {
31641         optionsMap.put(value, count - 1);
31642       }
31643     }
31644   };
31645
31646   // Check whether the select control has an option matching the given value
31647   self.hasOption = function(value) {
31648     return !!optionsMap.get(value);
31649   };
31650
31651
31652   self.registerOption = function(optionScope, optionElement, optionAttrs, hasDynamicValueAttr, interpolateTextFn) {
31653
31654     if (hasDynamicValueAttr) {
31655       // either "value" is interpolated directly, or set by ngValue
31656       var oldVal;
31657       optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
31658         if (isDefined(oldVal)) {
31659           self.removeOption(oldVal);
31660         }
31661         oldVal = newVal;
31662         self.addOption(newVal, optionElement);
31663       });
31664     } else if (interpolateTextFn) {
31665       // The text content is interpolated
31666       optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
31667         optionAttrs.$set('value', newVal);
31668         if (oldVal !== newVal) {
31669           self.removeOption(oldVal);
31670         }
31671         self.addOption(newVal, optionElement);
31672       });
31673     } else {
31674       // The value attribute is static
31675       self.addOption(optionAttrs.value, optionElement);
31676     }
31677
31678     optionElement.on('$destroy', function() {
31679       self.removeOption(optionAttrs.value);
31680       self.ngModelCtrl.$render();
31681     });
31682   };
31683 }];
31684
31685 /**
31686  * @ngdoc directive
31687  * @name select
31688  * @restrict E
31689  *
31690  * @description
31691  * HTML `SELECT` element with angular data-binding.
31692  *
31693  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
31694  * between the scope and the `<select>` control (including setting default values).
31695  * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
31696  * {@link ngOptions `ngOptions`} directives.
31697  *
31698  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
31699  * to the model identified by the `ngModel` directive. With static or repeated options, this is
31700  * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
31701  * For dynamic options, use interpolation inside the `value` attribute or the `textContent`. Using
31702  * {@link ngValue ngValue} is also possible (as it sets the `value` attribute), and will take
31703  * precedence over `value` and `textContent`.
31704  *
31705  * <div class="alert alert-warning">
31706  * Note that the value of a `select` directive used without `ngOptions` is always a string.
31707  * When the model needs to be bound to a non-string value, you must either explicitly convert it
31708  * using a directive (see example below) or use `ngOptions` to specify the set of options.
31709  * This is because an option element can only be bound to string values at present.
31710  * </div>
31711  *
31712  * If the viewValue of `ngModel` does not match any of the options, then the control
31713  * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
31714  *
31715  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
31716  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
31717  * option. See example below for demonstration.
31718  *
31719  * <div class="alert alert-info">
31720  * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
31721  * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
31722  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
31723  * comprehension expression, and additionally in reducing memory and increasing speed by not creating
31724  * a new scope for each repeated instance.
31725  * </div>
31726  *
31727  *
31728  * @param {string} ngModel Assignable angular expression to data-bind to.
31729  * @param {string=} name Property name of the form under which the control is published.
31730  * @param {string=} multiple Allows multiple options to be selected. The selected values will be
31731  *     bound to the model as an array.
31732  * @param {string=} required Sets `required` validation error key if the value is not entered.
31733  * @param {string=} ngRequired Adds required attribute and required validation constraint to
31734  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
31735  * when you want to data-bind to the required attribute.
31736  * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
31737  *    interaction with the select element.
31738  * @param {string=} ngOptions sets the options that the select is populated with and defines what is
31739  * set on the model on selection. See {@link ngOptions `ngOptions`}.
31740  *
31741  * @example
31742  * ### Simple `select` elements with static options
31743  *
31744  * <example name="static-select" module="staticSelect">
31745  * <file name="index.html">
31746  * <div ng-controller="ExampleController">
31747  *   <form name="myForm">
31748  *     <label for="singleSelect"> Single select: </label><br>
31749  *     <select name="singleSelect" ng-model="data.singleSelect">
31750  *       <option value="option-1">Option 1</option>
31751  *       <option value="option-2">Option 2</option>
31752  *     </select><br>
31753  *
31754  *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
31755  *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
31756  *       <option value="">---Please select---</option> <!-- not selected / blank option -->
31757  *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
31758  *       <option value="option-2">Option 2</option>
31759  *     </select><br>
31760  *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
31761  *     <tt>singleSelect = {{data.singleSelect}}</tt>
31762  *
31763  *     <hr>
31764  *     <label for="multipleSelect"> Multiple select: </label><br>
31765  *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
31766  *       <option value="option-1">Option 1</option>
31767  *       <option value="option-2">Option 2</option>
31768  *       <option value="option-3">Option 3</option>
31769  *     </select><br>
31770  *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
31771  *   </form>
31772  * </div>
31773  * </file>
31774  * <file name="app.js">
31775  *  angular.module('staticSelect', [])
31776  *    .controller('ExampleController', ['$scope', function($scope) {
31777  *      $scope.data = {
31778  *       singleSelect: null,
31779  *       multipleSelect: [],
31780  *       option1: 'option-1'
31781  *      };
31782  *
31783  *      $scope.forceUnknownOption = function() {
31784  *        $scope.data.singleSelect = 'nonsense';
31785  *      };
31786  *   }]);
31787  * </file>
31788  *</example>
31789  *
31790  * ### Using `ngRepeat` to generate `select` options
31791  * <example name="ngrepeat-select" module="ngrepeatSelect">
31792  * <file name="index.html">
31793  * <div ng-controller="ExampleController">
31794  *   <form name="myForm">
31795  *     <label for="repeatSelect"> Repeat select: </label>
31796  *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
31797  *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
31798  *     </select>
31799  *   </form>
31800  *   <hr>
31801  *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
31802  * </div>
31803  * </file>
31804  * <file name="app.js">
31805  *  angular.module('ngrepeatSelect', [])
31806  *    .controller('ExampleController', ['$scope', function($scope) {
31807  *      $scope.data = {
31808  *       repeatSelect: null,
31809  *       availableOptions: [
31810  *         {id: '1', name: 'Option A'},
31811  *         {id: '2', name: 'Option B'},
31812  *         {id: '3', name: 'Option C'}
31813  *       ]
31814  *      };
31815  *   }]);
31816  * </file>
31817  *</example>
31818  *
31819  *
31820  * ### Using `select` with `ngOptions` and setting a default value
31821  * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
31822  *
31823  * <example name="select-with-default-values" module="defaultValueSelect">
31824  * <file name="index.html">
31825  * <div ng-controller="ExampleController">
31826  *   <form name="myForm">
31827  *     <label for="mySelect">Make a choice:</label>
31828  *     <select name="mySelect" id="mySelect"
31829  *       ng-options="option.name for option in data.availableOptions track by option.id"
31830  *       ng-model="data.selectedOption"></select>
31831  *   </form>
31832  *   <hr>
31833  *   <tt>option = {{data.selectedOption}}</tt><br/>
31834  * </div>
31835  * </file>
31836  * <file name="app.js">
31837  *  angular.module('defaultValueSelect', [])
31838  *    .controller('ExampleController', ['$scope', function($scope) {
31839  *      $scope.data = {
31840  *       availableOptions: [
31841  *         {id: '1', name: 'Option A'},
31842  *         {id: '2', name: 'Option B'},
31843  *         {id: '3', name: 'Option C'}
31844  *       ],
31845  *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
31846  *       };
31847  *   }]);
31848  * </file>
31849  *</example>
31850  *
31851  *
31852  * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
31853  *
31854  * <example name="select-with-non-string-options" module="nonStringSelect">
31855  *   <file name="index.html">
31856  *     <select ng-model="model.id" convert-to-number>
31857  *       <option value="0">Zero</option>
31858  *       <option value="1">One</option>
31859  *       <option value="2">Two</option>
31860  *     </select>
31861  *     {{ model }}
31862  *   </file>
31863  *   <file name="app.js">
31864  *     angular.module('nonStringSelect', [])
31865  *       .run(function($rootScope) {
31866  *         $rootScope.model = { id: 2 };
31867  *       })
31868  *       .directive('convertToNumber', function() {
31869  *         return {
31870  *           require: 'ngModel',
31871  *           link: function(scope, element, attrs, ngModel) {
31872  *             ngModel.$parsers.push(function(val) {
31873  *               return parseInt(val, 10);
31874  *             });
31875  *             ngModel.$formatters.push(function(val) {
31876  *               return '' + val;
31877  *             });
31878  *           }
31879  *         };
31880  *       });
31881  *   </file>
31882  *   <file name="protractor.js" type="protractor">
31883  *     it('should initialize to model', function() {
31884  *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
31885  *     });
31886  *   </file>
31887  * </example>
31888  *
31889  */
31890 var selectDirective = function() {
31891
31892   return {
31893     restrict: 'E',
31894     require: ['select', '?ngModel'],
31895     controller: SelectController,
31896     priority: 1,
31897     link: {
31898       pre: selectPreLink,
31899       post: selectPostLink
31900     }
31901   };
31902
31903   function selectPreLink(scope, element, attr, ctrls) {
31904
31905       // if ngModel is not defined, we don't need to do anything
31906       var ngModelCtrl = ctrls[1];
31907       if (!ngModelCtrl) return;
31908
31909       var selectCtrl = ctrls[0];
31910
31911       selectCtrl.ngModelCtrl = ngModelCtrl;
31912
31913       // When the selected item(s) changes we delegate getting the value of the select control
31914       // to the `readValue` method, which can be changed if the select can have multiple
31915       // selected values or if the options are being generated by `ngOptions`
31916       element.on('change', function() {
31917         scope.$apply(function() {
31918           ngModelCtrl.$setViewValue(selectCtrl.readValue());
31919         });
31920       });
31921
31922       // If the select allows multiple values then we need to modify how we read and write
31923       // values from and to the control; also what it means for the value to be empty and
31924       // we have to add an extra watch since ngModel doesn't work well with arrays - it
31925       // doesn't trigger rendering if only an item in the array changes.
31926       if (attr.multiple) {
31927
31928         // Read value now needs to check each option to see if it is selected
31929         selectCtrl.readValue = function readMultipleValue() {
31930           var array = [];
31931           forEach(element.find('option'), function(option) {
31932             if (option.selected) {
31933               array.push(option.value);
31934             }
31935           });
31936           return array;
31937         };
31938
31939         // Write value now needs to set the selected property of each matching option
31940         selectCtrl.writeValue = function writeMultipleValue(value) {
31941           var items = new HashMap(value);
31942           forEach(element.find('option'), function(option) {
31943             option.selected = isDefined(items.get(option.value));
31944           });
31945         };
31946
31947         // we have to do it on each watch since ngModel watches reference, but
31948         // we need to work of an array, so we need to see if anything was inserted/removed
31949         var lastView, lastViewRef = NaN;
31950         scope.$watch(function selectMultipleWatch() {
31951           if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
31952             lastView = shallowCopy(ngModelCtrl.$viewValue);
31953             ngModelCtrl.$render();
31954           }
31955           lastViewRef = ngModelCtrl.$viewValue;
31956         });
31957
31958         // If we are a multiple select then value is now a collection
31959         // so the meaning of $isEmpty changes
31960         ngModelCtrl.$isEmpty = function(value) {
31961           return !value || value.length === 0;
31962         };
31963
31964       }
31965     }
31966
31967     function selectPostLink(scope, element, attrs, ctrls) {
31968       // if ngModel is not defined, we don't need to do anything
31969       var ngModelCtrl = ctrls[1];
31970       if (!ngModelCtrl) return;
31971
31972       var selectCtrl = ctrls[0];
31973
31974       // We delegate rendering to the `writeValue` method, which can be changed
31975       // if the select can have multiple selected values or if the options are being
31976       // generated by `ngOptions`.
31977       // This must be done in the postLink fn to prevent $render to be called before
31978       // all nodes have been linked correctly.
31979       ngModelCtrl.$render = function() {
31980         selectCtrl.writeValue(ngModelCtrl.$viewValue);
31981       };
31982     }
31983 };
31984
31985
31986 // The option directive is purely designed to communicate the existence (or lack of)
31987 // of dynamically created (and destroyed) option elements to their containing select
31988 // directive via its controller.
31989 var optionDirective = ['$interpolate', function($interpolate) {
31990   return {
31991     restrict: 'E',
31992     priority: 100,
31993     compile: function(element, attr) {
31994       var hasDynamicValueAttr, interpolateTextFn;
31995
31996       if (isDefined(attr.ngValue)) {
31997         // If ngValue is defined, then the value attr will be set to the result of the expression,
31998         // and the selectCtrl must set up an observer
31999         hasDynamicValueAttr = true;
32000       } else if (isDefined(attr.value)) {
32001         // If the value attr contains an interpolation, the selectCtrl must set up an observer
32002         hasDynamicValueAttr = $interpolate(attr.value, true);
32003       } else {
32004         // If the value attribute is not defined then we fall back to the
32005         // text content of the option element, which may be interpolated
32006         interpolateTextFn = $interpolate(element.text(), true);
32007         if (!interpolateTextFn) {
32008           attr.$set('value', element.text());
32009         }
32010       }
32011
32012       return function(scope, element, attr) {
32013         // This is an optimization over using ^^ since we don't want to have to search
32014         // all the way to the root of the DOM for every single option element
32015         var selectCtrlName = '$selectController',
32016             parent = element.parent(),
32017             selectCtrl = parent.data(selectCtrlName) ||
32018               parent.parent().data(selectCtrlName); // in case we are in optgroup
32019
32020         if (selectCtrl) {
32021           selectCtrl.registerOption(scope, element, attr, hasDynamicValueAttr, interpolateTextFn);
32022         }
32023       };
32024     }
32025   };
32026 }];
32027
32028 /**
32029  * @ngdoc directive
32030  * @name ngRequired
32031  * @restrict A
32032  *
32033  * @description
32034  *
32035  * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
32036  * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
32037  * applied to custom controls.
32038  *
32039  * The directive sets the `required` attribute on the element if the Angular expression inside
32040  * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
32041  * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
32042  * for more info.
32043  *
32044  * The validator will set the `required` error key to true if the `required` attribute is set and
32045  * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
32046  * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
32047  * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
32048  * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
32049  *
32050  * @example
32051  * <example name="ngRequiredDirective" module="ngRequiredExample">
32052  *   <file name="index.html">
32053  *     <script>
32054  *       angular.module('ngRequiredExample', [])
32055  *         .controller('ExampleController', ['$scope', function($scope) {
32056  *           $scope.required = true;
32057  *         }]);
32058  *     </script>
32059  *     <div ng-controller="ExampleController">
32060  *       <form name="form">
32061  *         <label for="required">Toggle required: </label>
32062  *         <input type="checkbox" ng-model="required" id="required" />
32063  *         <br>
32064  *         <label for="input">This input must be filled if `required` is true: </label>
32065  *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
32066  *         <hr>
32067  *         required error set? = <code>{{form.input.$error.required}}</code><br>
32068  *         model = <code>{{model}}</code>
32069  *       </form>
32070  *     </div>
32071  *   </file>
32072  *   <file name="protractor.js" type="protractor">
32073        var required = element(by.binding('form.input.$error.required'));
32074        var model = element(by.binding('model'));
32075        var input = element(by.id('input'));
32076
32077        it('should set the required error', function() {
32078          expect(required.getText()).toContain('true');
32079
32080          input.sendKeys('123');
32081          expect(required.getText()).not.toContain('true');
32082          expect(model.getText()).toContain('123');
32083        });
32084  *   </file>
32085  * </example>
32086  */
32087 var requiredDirective = function() {
32088   return {
32089     restrict: 'A',
32090     require: '?ngModel',
32091     link: function(scope, elm, attr, ctrl) {
32092       if (!ctrl) return;
32093       attr.required = true; // force truthy in case we are on non input element
32094
32095       ctrl.$validators.required = function(modelValue, viewValue) {
32096         return !attr.required || !ctrl.$isEmpty(viewValue);
32097       };
32098
32099       attr.$observe('required', function() {
32100         ctrl.$validate();
32101       });
32102     }
32103   };
32104 };
32105
32106 /**
32107  * @ngdoc directive
32108  * @name ngPattern
32109  *
32110  * @description
32111  *
32112  * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
32113  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
32114  *
32115  * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
32116  * does not match a RegExp which is obtained by evaluating the Angular expression given in the
32117  * `ngPattern` attribute value:
32118  * * If the expression evaluates to a RegExp object, then this is used directly.
32119  * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
32120  * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
32121  *
32122  * <div class="alert alert-info">
32123  * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32124  * start at the index of the last search's match, thus not taking the whole input value into
32125  * account.
32126  * </div>
32127  *
32128  * <div class="alert alert-info">
32129  * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
32130  * differences:
32131  * <ol>
32132  *   <li>
32133  *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
32134  *     not available.
32135  *   </li>
32136  *   <li>
32137  *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
32138  *     interpolated.
32139  *   </li>
32140  * </ol>
32141  * </div>
32142  *
32143  * @example
32144  * <example name="ngPatternDirective" module="ngPatternExample">
32145  *   <file name="index.html">
32146  *     <script>
32147  *       angular.module('ngPatternExample', [])
32148  *         .controller('ExampleController', ['$scope', function($scope) {
32149  *           $scope.regex = '\\d+';
32150  *         }]);
32151  *     </script>
32152  *     <div ng-controller="ExampleController">
32153  *       <form name="form">
32154  *         <label for="regex">Set a pattern (regex string): </label>
32155  *         <input type="text" ng-model="regex" id="regex" />
32156  *         <br>
32157  *         <label for="input">This input is restricted by the current pattern: </label>
32158  *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
32159  *         <hr>
32160  *         input valid? = <code>{{form.input.$valid}}</code><br>
32161  *         model = <code>{{model}}</code>
32162  *       </form>
32163  *     </div>
32164  *   </file>
32165  *   <file name="protractor.js" type="protractor">
32166        var model = element(by.binding('model'));
32167        var input = element(by.id('input'));
32168
32169        it('should validate the input with the default pattern', function() {
32170          input.sendKeys('aaa');
32171          expect(model.getText()).not.toContain('aaa');
32172
32173          input.clear().then(function() {
32174            input.sendKeys('123');
32175            expect(model.getText()).toContain('123');
32176          });
32177        });
32178  *   </file>
32179  * </example>
32180  */
32181 var patternDirective = function() {
32182   return {
32183     restrict: 'A',
32184     require: '?ngModel',
32185     link: function(scope, elm, attr, ctrl) {
32186       if (!ctrl) return;
32187
32188       var regexp, patternExp = attr.ngPattern || attr.pattern;
32189       attr.$observe('pattern', function(regex) {
32190         if (isString(regex) && regex.length > 0) {
32191           regex = new RegExp('^' + regex + '$');
32192         }
32193
32194         if (regex && !regex.test) {
32195           throw minErr('ngPattern')('noregexp',
32196             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
32197             regex, startingTag(elm));
32198         }
32199
32200         regexp = regex || undefined;
32201         ctrl.$validate();
32202       });
32203
32204       ctrl.$validators.pattern = function(modelValue, viewValue) {
32205         // HTML5 pattern constraint validates the input value, so we validate the viewValue
32206         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
32207       };
32208     }
32209   };
32210 };
32211
32212 /**
32213  * @ngdoc directive
32214  * @name ngMaxlength
32215  *
32216  * @description
32217  *
32218  * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
32219  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
32220  *
32221  * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
32222  * is longer than the integer obtained by evaluating the Angular expression given in the
32223  * `ngMaxlength` attribute value.
32224  *
32225  * <div class="alert alert-info">
32226  * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
32227  * differences:
32228  * <ol>
32229  *   <li>
32230  *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
32231  *     validation is not available.
32232  *   </li>
32233  *   <li>
32234  *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
32235  *     interpolated.
32236  *   </li>
32237  * </ol>
32238  * </div>
32239  *
32240  * @example
32241  * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
32242  *   <file name="index.html">
32243  *     <script>
32244  *       angular.module('ngMaxlengthExample', [])
32245  *         .controller('ExampleController', ['$scope', function($scope) {
32246  *           $scope.maxlength = 5;
32247  *         }]);
32248  *     </script>
32249  *     <div ng-controller="ExampleController">
32250  *       <form name="form">
32251  *         <label for="maxlength">Set a maxlength: </label>
32252  *         <input type="number" ng-model="maxlength" id="maxlength" />
32253  *         <br>
32254  *         <label for="input">This input is restricted by the current maxlength: </label>
32255  *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
32256  *         <hr>
32257  *         input valid? = <code>{{form.input.$valid}}</code><br>
32258  *         model = <code>{{model}}</code>
32259  *       </form>
32260  *     </div>
32261  *   </file>
32262  *   <file name="protractor.js" type="protractor">
32263        var model = element(by.binding('model'));
32264        var input = element(by.id('input'));
32265
32266        it('should validate the input with the default maxlength', function() {
32267          input.sendKeys('abcdef');
32268          expect(model.getText()).not.toContain('abcdef');
32269
32270          input.clear().then(function() {
32271            input.sendKeys('abcde');
32272            expect(model.getText()).toContain('abcde');
32273          });
32274        });
32275  *   </file>
32276  * </example>
32277  */
32278 var maxlengthDirective = function() {
32279   return {
32280     restrict: 'A',
32281     require: '?ngModel',
32282     link: function(scope, elm, attr, ctrl) {
32283       if (!ctrl) return;
32284
32285       var maxlength = -1;
32286       attr.$observe('maxlength', function(value) {
32287         var intVal = toInt(value);
32288         maxlength = isNumberNaN(intVal) ? -1 : intVal;
32289         ctrl.$validate();
32290       });
32291       ctrl.$validators.maxlength = function(modelValue, viewValue) {
32292         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
32293       };
32294     }
32295   };
32296 };
32297
32298 /**
32299  * @ngdoc directive
32300  * @name ngMinlength
32301  *
32302  * @description
32303  *
32304  * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
32305  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
32306  *
32307  * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
32308  * is shorter than the integer obtained by evaluating the Angular expression given in the
32309  * `ngMinlength` attribute value.
32310  *
32311  * <div class="alert alert-info">
32312  * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
32313  * differences:
32314  * <ol>
32315  *   <li>
32316  *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
32317  *     validation is not available.
32318  *   </li>
32319  *   <li>
32320  *     The `ngMinlength` value must be an expression, while the `minlength` value must be
32321  *     interpolated.
32322  *   </li>
32323  * </ol>
32324  * </div>
32325  *
32326  * @example
32327  * <example name="ngMinlengthDirective" module="ngMinlengthExample">
32328  *   <file name="index.html">
32329  *     <script>
32330  *       angular.module('ngMinlengthExample', [])
32331  *         .controller('ExampleController', ['$scope', function($scope) {
32332  *           $scope.minlength = 3;
32333  *         }]);
32334  *     </script>
32335  *     <div ng-controller="ExampleController">
32336  *       <form name="form">
32337  *         <label for="minlength">Set a minlength: </label>
32338  *         <input type="number" ng-model="minlength" id="minlength" />
32339  *         <br>
32340  *         <label for="input">This input is restricted by the current minlength: </label>
32341  *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
32342  *         <hr>
32343  *         input valid? = <code>{{form.input.$valid}}</code><br>
32344  *         model = <code>{{model}}</code>
32345  *       </form>
32346  *     </div>
32347  *   </file>
32348  *   <file name="protractor.js" type="protractor">
32349        var model = element(by.binding('model'));
32350        var input = element(by.id('input'));
32351
32352        it('should validate the input with the default minlength', function() {
32353          input.sendKeys('ab');
32354          expect(model.getText()).not.toContain('ab');
32355
32356          input.sendKeys('abc');
32357          expect(model.getText()).toContain('abc');
32358        });
32359  *   </file>
32360  * </example>
32361  */
32362 var minlengthDirective = function() {
32363   return {
32364     restrict: 'A',
32365     require: '?ngModel',
32366     link: function(scope, elm, attr, ctrl) {
32367       if (!ctrl) return;
32368
32369       var minlength = 0;
32370       attr.$observe('minlength', function(value) {
32371         minlength = toInt(value) || 0;
32372         ctrl.$validate();
32373       });
32374       ctrl.$validators.minlength = function(modelValue, viewValue) {
32375         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
32376       };
32377     }
32378   };
32379 };
32380
32381 if (window.angular.bootstrap) {
32382   //AngularJS is already loaded, so we can return here...
32383   if (window.console) {
32384     console.log('WARNING: Tried to load angular more than once.');
32385   }
32386   return;
32387 }
32388
32389 //try to bind to jquery now so that one can write jqLite(document).ready()
32390 //but we will rebind on bootstrap again.
32391 bindJQuery();
32392
32393 publishExternalAPI(angular);
32394
32395 angular.module("ngLocale", [], ["$provide", function($provide) {
32396 var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
32397 function getDecimals(n) {
32398   n = n + '';
32399   var i = n.indexOf('.');
32400   return (i == -1) ? 0 : n.length - i - 1;
32401 }
32402
32403 function getVF(n, opt_precision) {
32404   var v = opt_precision;
32405
32406   if (undefined === v) {
32407     v = Math.min(getDecimals(n), 3);
32408   }
32409
32410   var base = Math.pow(10, v);
32411   var f = ((n * base) | 0) % base;
32412   return {v: v, f: f};
32413 }
32414
32415 $provide.value("$locale", {
32416   "DATETIME_FORMATS": {
32417     "AMPMS": [
32418       "AM",
32419       "PM"
32420     ],
32421     "DAY": [
32422       "Sunday",
32423       "Monday",
32424       "Tuesday",
32425       "Wednesday",
32426       "Thursday",
32427       "Friday",
32428       "Saturday"
32429     ],
32430     "ERANAMES": [
32431       "Before Christ",
32432       "Anno Domini"
32433     ],
32434     "ERAS": [
32435       "BC",
32436       "AD"
32437     ],
32438     "FIRSTDAYOFWEEK": 6,
32439     "MONTH": [
32440       "January",
32441       "February",
32442       "March",
32443       "April",
32444       "May",
32445       "June",
32446       "July",
32447       "August",
32448       "September",
32449       "October",
32450       "November",
32451       "December"
32452     ],
32453     "SHORTDAY": [
32454       "Sun",
32455       "Mon",
32456       "Tue",
32457       "Wed",
32458       "Thu",
32459       "Fri",
32460       "Sat"
32461     ],
32462     "SHORTMONTH": [
32463       "Jan",
32464       "Feb",
32465       "Mar",
32466       "Apr",
32467       "May",
32468       "Jun",
32469       "Jul",
32470       "Aug",
32471       "Sep",
32472       "Oct",
32473       "Nov",
32474       "Dec"
32475     ],
32476     "STANDALONEMONTH": [
32477       "January",
32478       "February",
32479       "March",
32480       "April",
32481       "May",
32482       "June",
32483       "July",
32484       "August",
32485       "September",
32486       "October",
32487       "November",
32488       "December"
32489     ],
32490     "WEEKENDRANGE": [
32491       5,
32492       6
32493     ],
32494     "fullDate": "EEEE, MMMM d, y",
32495     "longDate": "MMMM d, y",
32496     "medium": "MMM d, y h:mm:ss a",
32497     "mediumDate": "MMM d, y",
32498     "mediumTime": "h:mm:ss a",
32499     "short": "M/d/yy h:mm a",
32500     "shortDate": "M/d/yy",
32501     "shortTime": "h:mm a"
32502   },
32503   "NUMBER_FORMATS": {
32504     "CURRENCY_SYM": "$",
32505     "DECIMAL_SEP": ".",
32506     "GROUP_SEP": ",",
32507     "PATTERNS": [
32508       {
32509         "gSize": 3,
32510         "lgSize": 3,
32511         "maxFrac": 3,
32512         "minFrac": 0,
32513         "minInt": 1,
32514         "negPre": "-",
32515         "negSuf": "",
32516         "posPre": "",
32517         "posSuf": ""
32518       },
32519       {
32520         "gSize": 3,
32521         "lgSize": 3,
32522         "maxFrac": 2,
32523         "minFrac": 2,
32524         "minInt": 1,
32525         "negPre": "-\u00a4",
32526         "negSuf": "",
32527         "posPre": "\u00a4",
32528         "posSuf": ""
32529       }
32530     ]
32531   },
32532   "id": "en-us",
32533   "localeID": "en_US",
32534   "pluralCat": function(n, opt_precision) {  var i = n | 0;  var vf = getVF(n, opt_precision);  if (i == 1 && vf.v == 0) {    return PLURAL_CATEGORY.ONE;  }  return PLURAL_CATEGORY.OTHER;}
32535 });
32536 }]);
32537
32538   jqLite(window.document).ready(function() {
32539     angularInit(window.document, bootstrap);
32540   });
32541
32542 })(window);
32543
32544 !window.angular.$$csp().noInlineStyle && 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;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');