Built motion from commit 99feb03.|0.0.140
[motion.git] / public / bower_components / angular / angular.js
1 /**
2  * @license AngularJS v1.4.8
3  * (c) 2010-2015 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window, document, undefined) {'use strict';
7
8 /**
9  * @description
10  *
11  * This object provides a utility for producing rich Error messages within
12  * Angular. It can be called as follows:
13  *
14  * var exampleMinErr = minErr('example');
15  * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16  *
17  * The above creates an instance of minErr in the example namespace. The
18  * resulting error will have a namespaced error code of example.one.  The
19  * resulting error will replace {0} with the value of foo, and {1} with the
20  * value of bar. The object is not restricted in the number of arguments it can
21  * take.
22  *
23  * If fewer arguments are specified than necessary for interpolation, the extra
24  * interpolation markers will be preserved in the final string.
25  *
26  * Since data will be parsed statically during a build step, some restrictions
27  * are applied with respect to how minErr instances are created and called.
28  * Instances should have names of the form namespaceMinErr for a minErr created
29  * using minErr('namespace') . Error codes, namespaces and template strings
30  * should all be static strings, not variables or general expressions.
31  *
32  * @param {string} module The namespace to use for the new minErr instance.
33  * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
34  *   error from returned function, for cases when a particular type of error is useful.
35  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
36  */
37
38 function minErr(module, ErrorConstructor) {
39   ErrorConstructor = ErrorConstructor || Error;
40   return function() {
41     var 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.4.8/' +
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 jshint what variables are being exported */
73 /* global angular: true,
74   msie: true,
75   jqLite: true,
76   jQuery: true,
77   slice: true,
78   splice: true,
79   push: true,
80   toString: true,
81   ngMinErr: true,
82   angularModule: true,
83   uid: true,
84   REGEX_STRING_REGEXP: true,
85   VALIDITY_STATE_PROPERTY: true,
86
87   lowercase: true,
88   uppercase: true,
89   manualLowercase: true,
90   manualUppercase: true,
91   nodeName_: true,
92   isArrayLike: true,
93   forEach: true,
94   forEachSorted: true,
95   reverseParams: true,
96   nextUid: true,
97   setHashKey: true,
98   extend: true,
99   toInt: true,
100   inherit: true,
101   merge: true,
102   noop: true,
103   identity: true,
104   valueFn: true,
105   isUndefined: true,
106   isDefined: true,
107   isObject: true,
108   isBlankObject: true,
109   isString: true,
110   isNumber: true,
111   isDate: true,
112   isArray: true,
113   isFunction: true,
114   isRegExp: true,
115   isWindow: true,
116   isScope: true,
117   isFile: true,
118   isFormData: true,
119   isBlob: true,
120   isBoolean: true,
121   isPromiseLike: true,
122   trim: true,
123   escapeForRegexp: true,
124   isElement: true,
125   makeMap: true,
126   includes: true,
127   arrayRemove: true,
128   copy: true,
129   shallowCopy: true,
130   equals: true,
131   csp: true,
132   jq: true,
133   concat: true,
134   sliceArgs: true,
135   bind: true,
136   toJsonReplacer: true,
137   toJson: true,
138   fromJson: true,
139   convertTimezoneToLocal: true,
140   timezoneToOffset: true,
141   startingTag: true,
142   tryDecodeURIComponent: true,
143   parseKeyValue: true,
144   toKeyValue: true,
145   encodeUriSegment: true,
146   encodeUriQuery: true,
147   angularInit: true,
148   bootstrap: true,
149   getTestability: true,
150   snake_case: true,
151   bindJQuery: true,
152   assertArg: true,
153   assertArgFn: true,
154   assertNotHasOwnProperty: true,
155   getter: true,
156   getBlockNodes: true,
157   hasOwnProperty: true,
158   createMap: true,
159
160   NODE_TYPE_ELEMENT: true,
161   NODE_TYPE_ATTRIBUTE: true,
162   NODE_TYPE_TEXT: true,
163   NODE_TYPE_COMMENT: true,
164   NODE_TYPE_DOCUMENT: true,
165   NODE_TYPE_DOCUMENT_FRAGMENT: true,
166 */
167
168 ////////////////////////////////////
169
170 /**
171  * @ngdoc module
172  * @name ng
173  * @module ng
174  * @description
175  *
176  * # ng (core module)
177  * The ng module is loaded by default when an AngularJS application is started. The module itself
178  * contains the essential components for an AngularJS application to function. The table below
179  * lists a high level breakdown of each of the services/factories, filters, directives and testing
180  * components available within this core module.
181  *
182  * <div doc-module-components="ng"></div>
183  */
184
185 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
186
187 // The name of a form control's ValidityState property.
188 // This is used so that it's possible for internal tests to create mock ValidityStates.
189 var VALIDITY_STATE_PROPERTY = 'validity';
190
191 /**
192  * @ngdoc function
193  * @name angular.lowercase
194  * @module ng
195  * @kind function
196  *
197  * @description Converts the specified string to lowercase.
198  * @param {string} string String to be converted to lowercase.
199  * @returns {string} Lowercased string.
200  */
201 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
202 var hasOwnProperty = Object.prototype.hasOwnProperty;
203
204 /**
205  * @ngdoc function
206  * @name angular.uppercase
207  * @module ng
208  * @kind function
209  *
210  * @description Converts the specified string to uppercase.
211  * @param {string} string String to be converted to uppercase.
212  * @returns {string} Uppercased string.
213  */
214 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
215
216
217 var manualLowercase = function(s) {
218   /* jshint bitwise: false */
219   return isString(s)
220       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
221       : s;
222 };
223 var manualUppercase = function(s) {
224   /* jshint bitwise: false */
225   return isString(s)
226       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
227       : s;
228 };
229
230
231 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
232 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
233 // with correct but slower alternatives.
234 if ('i' !== 'I'.toLowerCase()) {
235   lowercase = manualLowercase;
236   uppercase = manualUppercase;
237 }
238
239
240 var
241     msie,             // holds major version number for IE, or NaN if UA is not IE.
242     jqLite,           // delay binding since jQuery could be loaded after us.
243     jQuery,           // delay binding
244     slice             = [].slice,
245     splice            = [].splice,
246     push              = [].push,
247     toString          = Object.prototype.toString,
248     getPrototypeOf    = Object.getPrototypeOf,
249     ngMinErr          = minErr('ng'),
250
251     /** @name angular */
252     angular           = window.angular || (window.angular = {}),
253     angularModule,
254     uid               = 0;
255
256 /**
257  * documentMode is an IE-only property
258  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
259  */
260 msie = document.documentMode;
261
262
263 /**
264  * @private
265  * @param {*} obj
266  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
267  *                   String ...)
268  */
269 function isArrayLike(obj) {
270
271   // `null`, `undefined` and `window` are not array-like
272   if (obj == null || isWindow(obj)) return false;
273
274   // arrays, strings and jQuery/jqLite objects are array like
275   // * jqLite is either the jQuery or jqLite constructor function
276   // * we have to check the existance of jqLite first as this method is called
277   //   via the forEach method when constructing the jqLite object in the first place
278   if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
279
280   // Support: iOS 8.2 (not reproducible in simulator)
281   // "length" in obj used to prevent JIT error (gh-11508)
282   var length = "length" in Object(obj) && obj.length;
283
284   // NodeList objects (with `item` method) and
285   // other objects with suitable length characteristics are array-like
286   return isNumber(length) &&
287     (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
288 }
289
290 /**
291  * @ngdoc function
292  * @name angular.forEach
293  * @module ng
294  * @kind function
295  *
296  * @description
297  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
298  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
299  * is the value of an object property or an array element, `key` is the object property key or
300  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
301  *
302  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
303  * using the `hasOwnProperty` method.
304  *
305  * Unlike ES262's
306  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
307  * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
308  * return the value provided.
309  *
310    ```js
311      var values = {name: 'misko', gender: 'male'};
312      var log = [];
313      angular.forEach(values, function(value, key) {
314        this.push(key + ': ' + value);
315      }, log);
316      expect(log).toEqual(['name: misko', 'gender: male']);
317    ```
318  *
319  * @param {Object|Array} obj Object to iterate over.
320  * @param {Function} iterator Iterator function.
321  * @param {Object=} context Object to become context (`this`) for the iterator function.
322  * @returns {Object|Array} Reference to `obj`.
323  */
324
325 function forEach(obj, iterator, context) {
326   var key, length;
327   if (obj) {
328     if (isFunction(obj)) {
329       for (key in obj) {
330         // Need to check if hasOwnProperty exists,
331         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
332         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
333           iterator.call(context, obj[key], key, obj);
334         }
335       }
336     } else if (isArray(obj) || isArrayLike(obj)) {
337       var isPrimitive = typeof obj !== 'object';
338       for (key = 0, length = obj.length; key < length; key++) {
339         if (isPrimitive || key in obj) {
340           iterator.call(context, obj[key], key, obj);
341         }
342       }
343     } else if (obj.forEach && obj.forEach !== forEach) {
344         obj.forEach(iterator, context, obj);
345     } else if (isBlankObject(obj)) {
346       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
347       for (key in obj) {
348         iterator.call(context, obj[key], key, obj);
349       }
350     } else if (typeof obj.hasOwnProperty === 'function') {
351       // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
352       for (key in obj) {
353         if (obj.hasOwnProperty(key)) {
354           iterator.call(context, obj[key], key, obj);
355         }
356       }
357     } else {
358       // Slow path for objects which do not have a method `hasOwnProperty`
359       for (key in obj) {
360         if (hasOwnProperty.call(obj, key)) {
361           iterator.call(context, obj[key], key, obj);
362         }
363       }
364     }
365   }
366   return obj;
367 }
368
369 function forEachSorted(obj, iterator, context) {
370   var keys = Object.keys(obj).sort();
371   for (var i = 0; i < keys.length; i++) {
372     iterator.call(context, obj[keys[i]], keys[i]);
373   }
374   return keys;
375 }
376
377
378 /**
379  * when using forEach the params are value, key, but it is often useful to have key, value.
380  * @param {function(string, *)} iteratorFn
381  * @returns {function(*, string)}
382  */
383 function reverseParams(iteratorFn) {
384   return function(value, key) { iteratorFn(key, value); };
385 }
386
387 /**
388  * A consistent way of creating unique IDs in angular.
389  *
390  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
391  * we hit number precision issues in JavaScript.
392  *
393  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
394  *
395  * @returns {number} an unique alpha-numeric string
396  */
397 function nextUid() {
398   return ++uid;
399 }
400
401
402 /**
403  * Set or clear the hashkey for an object.
404  * @param obj object
405  * @param h the hashkey (!truthy to delete the hashkey)
406  */
407 function setHashKey(obj, h) {
408   if (h) {
409     obj.$$hashKey = h;
410   } else {
411     delete obj.$$hashKey;
412   }
413 }
414
415
416 function baseExtend(dst, objs, deep) {
417   var h = dst.$$hashKey;
418
419   for (var i = 0, ii = objs.length; i < ii; ++i) {
420     var obj = objs[i];
421     if (!isObject(obj) && !isFunction(obj)) continue;
422     var keys = Object.keys(obj);
423     for (var j = 0, jj = keys.length; j < jj; j++) {
424       var key = keys[j];
425       var src = obj[key];
426
427       if (deep && isObject(src)) {
428         if (isDate(src)) {
429           dst[key] = new Date(src.valueOf());
430         } else if (isRegExp(src)) {
431           dst[key] = new RegExp(src);
432         } else if (src.nodeName) {
433           dst[key] = src.cloneNode(true);
434         } else if (isElement(src)) {
435           dst[key] = src.clone();
436         } else {
437           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
438           baseExtend(dst[key], [src], true);
439         }
440       } else {
441         dst[key] = src;
442       }
443     }
444   }
445
446   setHashKey(dst, h);
447   return dst;
448 }
449
450 /**
451  * @ngdoc function
452  * @name angular.extend
453  * @module ng
454  * @kind function
455  *
456  * @description
457  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
458  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
459  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
460  *
461  * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
462  * {@link angular.merge} for this.
463  *
464  * @param {Object} dst Destination object.
465  * @param {...Object} src Source object(s).
466  * @returns {Object} Reference to `dst`.
467  */
468 function extend(dst) {
469   return baseExtend(dst, slice.call(arguments, 1), false);
470 }
471
472
473 /**
474 * @ngdoc function
475 * @name angular.merge
476 * @module ng
477 * @kind function
478 *
479 * @description
480 * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
481 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
482 * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
483 *
484 * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
485 * objects, performing a deep copy.
486 *
487 * @param {Object} dst Destination object.
488 * @param {...Object} src Source object(s).
489 * @returns {Object} Reference to `dst`.
490 */
491 function merge(dst) {
492   return baseExtend(dst, slice.call(arguments, 1), true);
493 }
494
495
496
497 function toInt(str) {
498   return parseInt(str, 10);
499 }
500
501
502 function inherit(parent, extra) {
503   return extend(Object.create(parent), extra);
504 }
505
506 /**
507  * @ngdoc function
508  * @name angular.noop
509  * @module ng
510  * @kind function
511  *
512  * @description
513  * A function that performs no operations. This function can be useful when writing code in the
514  * functional style.
515    ```js
516      function foo(callback) {
517        var result = calculateResult();
518        (callback || angular.noop)(result);
519      }
520    ```
521  */
522 function noop() {}
523 noop.$inject = [];
524
525
526 /**
527  * @ngdoc function
528  * @name angular.identity
529  * @module ng
530  * @kind function
531  *
532  * @description
533  * A function that returns its first argument. This function is useful when writing code in the
534  * functional style.
535  *
536    ```js
537      function transformer(transformationFn, value) {
538        return (transformationFn || angular.identity)(value);
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() {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`.
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
756 var trim = function(value) {
757   return isString(value) ? value.trim() : value;
758 };
759
760 // Copied from:
761 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
762 // Prereq: s is a string.
763 var escapeForRegexp = function(s) {
764   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
765            replace(/\x08/g, '\\x08');
766 };
767
768
769 /**
770  * @ngdoc function
771  * @name angular.isElement
772  * @module ng
773  * @kind function
774  *
775  * @description
776  * Determines if a reference is a DOM element (or wrapped jQuery element).
777  *
778  * @param {*} value Reference to check.
779  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
780  */
781 function isElement(node) {
782   return !!(node &&
783     (node.nodeName  // we are a direct element
784     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
785 }
786
787 /**
788  * @param str 'key1,key2,...'
789  * @returns {object} in the form of {key1:true, key2:true, ...}
790  */
791 function makeMap(str) {
792   var obj = {}, items = str.split(","), i;
793   for (i = 0; i < items.length; i++) {
794     obj[items[i]] = true;
795   }
796   return obj;
797 }
798
799
800 function nodeName_(element) {
801   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
802 }
803
804 function includes(array, obj) {
805   return Array.prototype.indexOf.call(array, obj) != -1;
806 }
807
808 function arrayRemove(array, value) {
809   var index = array.indexOf(value);
810   if (index >= 0) {
811     array.splice(index, 1);
812   }
813   return index;
814 }
815
816 /**
817  * @ngdoc function
818  * @name angular.copy
819  * @module ng
820  * @kind function
821  *
822  * @description
823  * Creates a deep copy of `source`, which should be an object or an array.
824  *
825  * * If no destination is supplied, a copy of the object or array is created.
826  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
827  *   are deleted and then all elements/properties from the source are copied to it.
828  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
829  * * If `source` is identical to 'destination' an exception will be thrown.
830  *
831  * @param {*} source The source that will be used to make a copy.
832  *                   Can be any type, including primitives, `null`, and `undefined`.
833  * @param {(Object|Array)=} destination Destination into which the source is copied. If
834  *     provided, must be of the same type as `source`.
835  * @returns {*} The copy or updated `destination`, if `destination` was specified.
836  *
837  * @example
838  <example module="copyExample">
839  <file name="index.html">
840  <div ng-controller="ExampleController">
841  <form novalidate class="simple-form">
842  Name: <input type="text" ng-model="user.name" /><br />
843  E-mail: <input type="email" ng-model="user.email" /><br />
844  Gender: <input type="radio" ng-model="user.gender" value="male" />male
845  <input type="radio" ng-model="user.gender" value="female" />female<br />
846  <button ng-click="reset()">RESET</button>
847  <button ng-click="update(user)">SAVE</button>
848  </form>
849  <pre>form = {{user | json}}</pre>
850  <pre>master = {{master | json}}</pre>
851  </div>
852
853  <script>
854   angular.module('copyExample', [])
855     .controller('ExampleController', ['$scope', function($scope) {
856       $scope.master= {};
857
858       $scope.update = function(user) {
859         // Example with 1 argument
860         $scope.master= angular.copy(user);
861       };
862
863       $scope.reset = function() {
864         // Example with 2 arguments
865         angular.copy($scope.master, $scope.user);
866       };
867
868       $scope.reset();
869     }]);
870  </script>
871  </file>
872  </example>
873  */
874 function copy(source, destination) {
875   var stackSource = [];
876   var stackDest = [];
877
878   if (destination) {
879     if (isTypedArray(destination)) {
880       throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
881     }
882     if (source === destination) {
883       throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
884     }
885
886     // Empty the destination object
887     if (isArray(destination)) {
888       destination.length = 0;
889     } else {
890       forEach(destination, function(value, key) {
891         if (key !== '$$hashKey') {
892           delete destination[key];
893         }
894       });
895     }
896
897     stackSource.push(source);
898     stackDest.push(destination);
899     return copyRecurse(source, destination);
900   }
901
902   return copyElement(source);
903
904   function copyRecurse(source, destination) {
905     var h = destination.$$hashKey;
906     var result, key;
907     if (isArray(source)) {
908       for (var i = 0, ii = source.length; i < ii; i++) {
909         destination.push(copyElement(source[i]));
910       }
911     } else if (isBlankObject(source)) {
912       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
913       for (key in source) {
914         destination[key] = copyElement(source[key]);
915       }
916     } else if (source && typeof source.hasOwnProperty === 'function') {
917       // Slow path, which must rely on hasOwnProperty
918       for (key in source) {
919         if (source.hasOwnProperty(key)) {
920           destination[key] = copyElement(source[key]);
921         }
922       }
923     } else {
924       // Slowest path --- hasOwnProperty can't be called as a method
925       for (key in source) {
926         if (hasOwnProperty.call(source, key)) {
927           destination[key] = copyElement(source[key]);
928         }
929       }
930     }
931     setHashKey(destination, h);
932     return destination;
933   }
934
935   function copyElement(source) {
936     // Simple values
937     if (!isObject(source)) {
938       return source;
939     }
940
941     // Already copied values
942     var index = stackSource.indexOf(source);
943     if (index !== -1) {
944       return stackDest[index];
945     }
946
947     if (isWindow(source) || isScope(source)) {
948       throw ngMinErr('cpws',
949         "Can't copy! Making copies of Window or Scope instances is not supported.");
950     }
951
952     var needsRecurse = false;
953     var destination;
954
955     if (isArray(source)) {
956       destination = [];
957       needsRecurse = true;
958     } else if (isTypedArray(source)) {
959       destination = new source.constructor(source);
960     } else if (isDate(source)) {
961       destination = new Date(source.getTime());
962     } else if (isRegExp(source)) {
963       destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
964       destination.lastIndex = source.lastIndex;
965     } else if (isFunction(source.cloneNode)) {
966         destination = source.cloneNode(true);
967     } else {
968       destination = Object.create(getPrototypeOf(source));
969       needsRecurse = true;
970     }
971
972     stackSource.push(source);
973     stackDest.push(destination);
974
975     return needsRecurse
976       ? copyRecurse(source, destination)
977       : destination;
978   }
979 }
980
981 /**
982  * Creates a shallow copy of an object, an array or a primitive.
983  *
984  * Assumes that there are no proto properties for objects.
985  */
986 function shallowCopy(src, dst) {
987   if (isArray(src)) {
988     dst = dst || [];
989
990     for (var i = 0, ii = src.length; i < ii; i++) {
991       dst[i] = src[i];
992     }
993   } else if (isObject(src)) {
994     dst = dst || {};
995
996     for (var key in src) {
997       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
998         dst[key] = src[key];
999       }
1000     }
1001   }
1002
1003   return dst || src;
1004 }
1005
1006
1007 /**
1008  * @ngdoc function
1009  * @name angular.equals
1010  * @module ng
1011  * @kind function
1012  *
1013  * @description
1014  * Determines if two objects or two values are equivalent. Supports value types, regular
1015  * expressions, arrays and objects.
1016  *
1017  * Two objects or values are considered equivalent if at least one of the following is true:
1018  *
1019  * * Both objects or values pass `===` comparison.
1020  * * Both objects or values are of the same type and all of their properties are equal by
1021  *   comparing them with `angular.equals`.
1022  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1023  * * Both values represent the same regular expression (In JavaScript,
1024  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1025  *   representation matches).
1026  *
1027  * During a property comparison, properties of `function` type and properties with names
1028  * that begin with `$` are ignored.
1029  *
1030  * Scope and DOMWindow objects are being compared only by identify (`===`).
1031  *
1032  * @param {*} o1 Object or value to compare.
1033  * @param {*} o2 Object or value to compare.
1034  * @returns {boolean} True if arguments are equal.
1035  */
1036 function equals(o1, o2) {
1037   if (o1 === o2) return true;
1038   if (o1 === null || o2 === null) return false;
1039   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1040   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1041   if (t1 == t2) {
1042     if (t1 == 'object') {
1043       if (isArray(o1)) {
1044         if (!isArray(o2)) return false;
1045         if ((length = o1.length) == o2.length) {
1046           for (key = 0; key < length; key++) {
1047             if (!equals(o1[key], o2[key])) return false;
1048           }
1049           return true;
1050         }
1051       } else if (isDate(o1)) {
1052         if (!isDate(o2)) return false;
1053         return equals(o1.getTime(), o2.getTime());
1054       } else if (isRegExp(o1)) {
1055         return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1056       } else {
1057         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1058           isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1059         keySet = createMap();
1060         for (key in o1) {
1061           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1062           if (!equals(o1[key], o2[key])) return false;
1063           keySet[key] = true;
1064         }
1065         for (key in o2) {
1066           if (!(key in keySet) &&
1067               key.charAt(0) !== '$' &&
1068               isDefined(o2[key]) &&
1069               !isFunction(o2[key])) return false;
1070         }
1071         return true;
1072       }
1073     }
1074   }
1075   return false;
1076 }
1077
1078 var csp = function() {
1079   if (!isDefined(csp.rules)) {
1080
1081
1082     var ngCspElement = (document.querySelector('[ng-csp]') ||
1083                     document.querySelector('[data-ng-csp]'));
1084
1085     if (ngCspElement) {
1086       var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1087                     ngCspElement.getAttribute('data-ng-csp');
1088       csp.rules = {
1089         noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1090         noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1091       };
1092     } else {
1093       csp.rules = {
1094         noUnsafeEval: noUnsafeEval(),
1095         noInlineStyle: false
1096       };
1097     }
1098   }
1099
1100   return csp.rules;
1101
1102   function noUnsafeEval() {
1103     try {
1104       /* jshint -W031, -W054 */
1105       new Function('');
1106       /* jshint +W031, +W054 */
1107       return false;
1108     } catch (e) {
1109       return true;
1110     }
1111   }
1112 };
1113
1114 /**
1115  * @ngdoc directive
1116  * @module ng
1117  * @name ngJq
1118  *
1119  * @element ANY
1120  * @param {string=} ngJq the name of the library available under `window`
1121  * to be used for angular.element
1122  * @description
1123  * Use this directive to force the angular.element library.  This should be
1124  * used to force either jqLite by leaving ng-jq blank or setting the name of
1125  * the jquery variable under window (eg. jQuery).
1126  *
1127  * Since angular looks for this directive when it is loaded (doesn't wait for the
1128  * DOMContentLoaded event), it must be placed on an element that comes before the script
1129  * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1130  * others ignored.
1131  *
1132  * @example
1133  * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1134  ```html
1135  <!doctype html>
1136  <html ng-app ng-jq>
1137  ...
1138  ...
1139  </html>
1140  ```
1141  * @example
1142  * This example shows how to use a jQuery based library of a different name.
1143  * The library name must be available at the top most 'window'.
1144  ```html
1145  <!doctype html>
1146  <html ng-app ng-jq="jQueryLib">
1147  ...
1148  ...
1149  </html>
1150  ```
1151  */
1152 var jq = function() {
1153   if (isDefined(jq.name_)) return jq.name_;
1154   var el;
1155   var i, ii = ngAttrPrefixes.length, prefix, name;
1156   for (i = 0; i < ii; ++i) {
1157     prefix = ngAttrPrefixes[i];
1158     if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1159       name = el.getAttribute(prefix + 'jq');
1160       break;
1161     }
1162   }
1163
1164   return (jq.name_ = name);
1165 };
1166
1167 function concat(array1, array2, index) {
1168   return array1.concat(slice.call(array2, index));
1169 }
1170
1171 function sliceArgs(args, startIndex) {
1172   return slice.call(args, startIndex || 0);
1173 }
1174
1175
1176 /* jshint -W101 */
1177 /**
1178  * @ngdoc function
1179  * @name angular.bind
1180  * @module ng
1181  * @kind function
1182  *
1183  * @description
1184  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1185  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1186  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1187  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1188  *
1189  * @param {Object} self Context which `fn` should be evaluated in.
1190  * @param {function()} fn Function to be bound.
1191  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1192  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1193  */
1194 /* jshint +W101 */
1195 function bind(self, fn) {
1196   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1197   if (isFunction(fn) && !(fn instanceof RegExp)) {
1198     return curryArgs.length
1199       ? function() {
1200           return arguments.length
1201             ? fn.apply(self, concat(curryArgs, arguments, 0))
1202             : fn.apply(self, curryArgs);
1203         }
1204       : function() {
1205           return arguments.length
1206             ? fn.apply(self, arguments)
1207             : fn.call(self);
1208         };
1209   } else {
1210     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1211     return fn;
1212   }
1213 }
1214
1215
1216 function toJsonReplacer(key, value) {
1217   var val = value;
1218
1219   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1220     val = undefined;
1221   } else if (isWindow(value)) {
1222     val = '$WINDOW';
1223   } else if (value &&  document === value) {
1224     val = '$DOCUMENT';
1225   } else if (isScope(value)) {
1226     val = '$SCOPE';
1227   }
1228
1229   return val;
1230 }
1231
1232
1233 /**
1234  * @ngdoc function
1235  * @name angular.toJson
1236  * @module ng
1237  * @kind function
1238  *
1239  * @description
1240  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1241  * stripped since angular uses this notation internally.
1242  *
1243  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1244  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1245  *    If set to an integer, the JSON output will contain that many spaces per indentation.
1246  * @returns {string|undefined} JSON-ified string representing `obj`.
1247  */
1248 function toJson(obj, pretty) {
1249   if (typeof obj === 'undefined') return undefined;
1250   if (!isNumber(pretty)) {
1251     pretty = pretty ? 2 : null;
1252   }
1253   return JSON.stringify(obj, toJsonReplacer, pretty);
1254 }
1255
1256
1257 /**
1258  * @ngdoc function
1259  * @name angular.fromJson
1260  * @module ng
1261  * @kind function
1262  *
1263  * @description
1264  * Deserializes a JSON string.
1265  *
1266  * @param {string} json JSON string to deserialize.
1267  * @returns {Object|Array|string|number} Deserialized JSON string.
1268  */
1269 function fromJson(json) {
1270   return isString(json)
1271       ? JSON.parse(json)
1272       : json;
1273 }
1274
1275
1276 function timezoneToOffset(timezone, fallback) {
1277   var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1278   return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1279 }
1280
1281
1282 function addDateMinutes(date, minutes) {
1283   date = new Date(date.getTime());
1284   date.setMinutes(date.getMinutes() + minutes);
1285   return date;
1286 }
1287
1288
1289 function convertTimezoneToLocal(date, timezone, reverse) {
1290   reverse = reverse ? -1 : 1;
1291   var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1292   return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1293 }
1294
1295
1296 /**
1297  * @returns {string} Returns the string representation of the element.
1298  */
1299 function startingTag(element) {
1300   element = jqLite(element).clone();
1301   try {
1302     // turns out IE does not let you set .html() on elements which
1303     // are not allowed to have children. So we just ignore it.
1304     element.empty();
1305   } catch (e) {}
1306   var elemHtml = jqLite('<div>').append(element).html();
1307   try {
1308     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1309         elemHtml.
1310           match(/^(<[^>]+>)/)[1].
1311           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1312   } catch (e) {
1313     return lowercase(elemHtml);
1314   }
1315
1316 }
1317
1318
1319 /////////////////////////////////////////////////
1320
1321 /**
1322  * Tries to decode the URI component without throwing an exception.
1323  *
1324  * @private
1325  * @param str value potential URI component to check.
1326  * @returns {boolean} True if `value` can be decoded
1327  * with the decodeURIComponent function.
1328  */
1329 function tryDecodeURIComponent(value) {
1330   try {
1331     return decodeURIComponent(value);
1332   } catch (e) {
1333     // Ignore any invalid uri component
1334   }
1335 }
1336
1337
1338 /**
1339  * Parses an escaped url query string into key-value pairs.
1340  * @returns {Object.<string,boolean|Array>}
1341  */
1342 function parseKeyValue(/**string*/keyValue) {
1343   var obj = {};
1344   forEach((keyValue || "").split('&'), function(keyValue) {
1345     var splitPoint, key, val;
1346     if (keyValue) {
1347       key = keyValue = keyValue.replace(/\+/g,'%20');
1348       splitPoint = keyValue.indexOf('=');
1349       if (splitPoint !== -1) {
1350         key = keyValue.substring(0, splitPoint);
1351         val = keyValue.substring(splitPoint + 1);
1352       }
1353       key = tryDecodeURIComponent(key);
1354       if (isDefined(key)) {
1355         val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1356         if (!hasOwnProperty.call(obj, key)) {
1357           obj[key] = val;
1358         } else if (isArray(obj[key])) {
1359           obj[key].push(val);
1360         } else {
1361           obj[key] = [obj[key],val];
1362         }
1363       }
1364     }
1365   });
1366   return obj;
1367 }
1368
1369 function toKeyValue(obj) {
1370   var parts = [];
1371   forEach(obj, function(value, key) {
1372     if (isArray(value)) {
1373       forEach(value, function(arrayValue) {
1374         parts.push(encodeUriQuery(key, true) +
1375                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1376       });
1377     } else {
1378     parts.push(encodeUriQuery(key, true) +
1379                (value === true ? '' : '=' + encodeUriQuery(value, true)));
1380     }
1381   });
1382   return parts.length ? parts.join('&') : '';
1383 }
1384
1385
1386 /**
1387  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1388  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1389  * segments:
1390  *    segment       = *pchar
1391  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1392  *    pct-encoded   = "%" HEXDIG HEXDIG
1393  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1394  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1395  *                     / "*" / "+" / "," / ";" / "="
1396  */
1397 function encodeUriSegment(val) {
1398   return encodeUriQuery(val, true).
1399              replace(/%26/gi, '&').
1400              replace(/%3D/gi, '=').
1401              replace(/%2B/gi, '+');
1402 }
1403
1404
1405 /**
1406  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1407  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1408  * encoded per http://tools.ietf.org/html/rfc3986:
1409  *    query       = *( pchar / "/" / "?" )
1410  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1411  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1412  *    pct-encoded   = "%" HEXDIG HEXDIG
1413  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1414  *                     / "*" / "+" / "," / ";" / "="
1415  */
1416 function encodeUriQuery(val, pctEncodeSpaces) {
1417   return encodeURIComponent(val).
1418              replace(/%40/gi, '@').
1419              replace(/%3A/gi, ':').
1420              replace(/%24/g, '$').
1421              replace(/%2C/gi, ',').
1422              replace(/%3B/gi, ';').
1423              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1424 }
1425
1426 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1427
1428 function getNgAttribute(element, ngAttr) {
1429   var attr, i, ii = ngAttrPrefixes.length;
1430   for (i = 0; i < ii; ++i) {
1431     attr = ngAttrPrefixes[i] + ngAttr;
1432     if (isString(attr = element.getAttribute(attr))) {
1433       return attr;
1434     }
1435   }
1436   return null;
1437 }
1438
1439 /**
1440  * @ngdoc directive
1441  * @name ngApp
1442  * @module ng
1443  *
1444  * @element ANY
1445  * @param {angular.Module} ngApp an optional application
1446  *   {@link angular.module module} name to load.
1447  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1448  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1449  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1450  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1451  *   tracking down the root of these bugs.
1452  *
1453  * @description
1454  *
1455  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1456  * designates the **root element** of the application and is typically placed near the root element
1457  * of the page - e.g. on the `<body>` or `<html>` tags.
1458  *
1459  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1460  * found in the document will be used to define the root element to auto-bootstrap as an
1461  * application. To run multiple applications in an HTML document you must manually bootstrap them using
1462  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1463  *
1464  * You can specify an **AngularJS module** to be used as the root module for the application.  This
1465  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1466  * should contain the application code needed or have dependencies on other modules that will
1467  * contain the code. See {@link angular.module} for more information.
1468  *
1469  * In the example below if the `ngApp` directive were not placed on the `html` element then the
1470  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1471  * would not be resolved to `3`.
1472  *
1473  * `ngApp` is the easiest, and most common way to bootstrap an application.
1474  *
1475  <example module="ngAppDemo">
1476    <file name="index.html">
1477    <div ng-controller="ngAppDemoController">
1478      I can add: {{a}} + {{b}} =  {{ a+b }}
1479    </div>
1480    </file>
1481    <file name="script.js">
1482    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1483      $scope.a = 1;
1484      $scope.b = 2;
1485    });
1486    </file>
1487  </example>
1488  *
1489  * Using `ngStrictDi`, you would see something like this:
1490  *
1491  <example ng-app-included="true">
1492    <file name="index.html">
1493    <div ng-app="ngAppStrictDemo" ng-strict-di>
1494        <div ng-controller="GoodController1">
1495            I can add: {{a}} + {{b}} =  {{ a+b }}
1496
1497            <p>This renders because the controller does not fail to
1498               instantiate, by using explicit annotation style (see
1499               script.js for details)
1500            </p>
1501        </div>
1502
1503        <div ng-controller="GoodController2">
1504            Name: <input ng-model="name"><br />
1505            Hello, {{name}}!
1506
1507            <p>This renders because the controller does not fail to
1508               instantiate, by using explicit annotation style
1509               (see script.js for details)
1510            </p>
1511        </div>
1512
1513        <div ng-controller="BadController">
1514            I can add: {{a}} + {{b}} =  {{ a+b }}
1515
1516            <p>The controller could not be instantiated, due to relying
1517               on automatic function annotations (which are disabled in
1518               strict mode). As such, the content of this section is not
1519               interpolated, and there should be an error in your web console.
1520            </p>
1521        </div>
1522    </div>
1523    </file>
1524    <file name="script.js">
1525    angular.module('ngAppStrictDemo', [])
1526      // BadController will fail to instantiate, due to relying on automatic function annotation,
1527      // rather than an explicit annotation
1528      .controller('BadController', function($scope) {
1529        $scope.a = 1;
1530        $scope.b = 2;
1531      })
1532      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1533      // due to using explicit annotations using the array style and $inject property, respectively.
1534      .controller('GoodController1', ['$scope', function($scope) {
1535        $scope.a = 1;
1536        $scope.b = 2;
1537      }])
1538      .controller('GoodController2', GoodController2);
1539      function GoodController2($scope) {
1540        $scope.name = "World";
1541      }
1542      GoodController2.$inject = ['$scope'];
1543    </file>
1544    <file name="style.css">
1545    div[ng-controller] {
1546        margin-bottom: 1em;
1547        -webkit-border-radius: 4px;
1548        border-radius: 4px;
1549        border: 1px solid;
1550        padding: .5em;
1551    }
1552    div[ng-controller^=Good] {
1553        border-color: #d6e9c6;
1554        background-color: #dff0d8;
1555        color: #3c763d;
1556    }
1557    div[ng-controller^=Bad] {
1558        border-color: #ebccd1;
1559        background-color: #f2dede;
1560        color: #a94442;
1561        margin-bottom: 0;
1562    }
1563    </file>
1564  </example>
1565  */
1566 function angularInit(element, bootstrap) {
1567   var appElement,
1568       module,
1569       config = {};
1570
1571   // The element `element` has priority over any other element
1572   forEach(ngAttrPrefixes, function(prefix) {
1573     var name = prefix + 'app';
1574
1575     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1576       appElement = element;
1577       module = element.getAttribute(name);
1578     }
1579   });
1580   forEach(ngAttrPrefixes, function(prefix) {
1581     var name = prefix + 'app';
1582     var candidate;
1583
1584     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1585       appElement = candidate;
1586       module = candidate.getAttribute(name);
1587     }
1588   });
1589   if (appElement) {
1590     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1591     bootstrap(appElement, module ? [module] : [], config);
1592   }
1593 }
1594
1595 /**
1596  * @ngdoc function
1597  * @name angular.bootstrap
1598  * @module ng
1599  * @description
1600  * Use this function to manually start up angular application.
1601  *
1602  * See: {@link guide/bootstrap Bootstrap}
1603  *
1604  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1605  * They must use {@link ng.directive:ngApp ngApp}.
1606  *
1607  * Angular will detect if it has been loaded into the browser more than once and only allow the
1608  * first loaded script to be bootstrapped and will report a warning to the browser console for
1609  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1610  * multiple instances of Angular try to work on the DOM.
1611  *
1612  * ```html
1613  * <!doctype html>
1614  * <html>
1615  * <body>
1616  * <div ng-controller="WelcomeController">
1617  *   {{greeting}}
1618  * </div>
1619  *
1620  * <script src="angular.js"></script>
1621  * <script>
1622  *   var app = angular.module('demo', [])
1623  *   .controller('WelcomeController', function($scope) {
1624  *       $scope.greeting = 'Welcome!';
1625  *   });
1626  *   angular.bootstrap(document, ['demo']);
1627  * </script>
1628  * </body>
1629  * </html>
1630  * ```
1631  *
1632  * @param {DOMElement} element DOM element which is the root of angular application.
1633  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1634  *     Each item in the array should be the name of a predefined module or a (DI annotated)
1635  *     function that will be invoked by the injector as a `config` block.
1636  *     See: {@link angular.module modules}
1637  * @param {Object=} config an object for defining configuration options for the application. The
1638  *     following keys are supported:
1639  *
1640  * * `strictDi` - disable automatic function annotation for the application. This is meant to
1641  *   assist in finding bugs which break minified code. Defaults to `false`.
1642  *
1643  * @returns {auto.$injector} Returns the newly created injector for this app.
1644  */
1645 function bootstrap(element, modules, config) {
1646   if (!isObject(config)) config = {};
1647   var defaultConfig = {
1648     strictDi: false
1649   };
1650   config = extend(defaultConfig, config);
1651   var doBootstrap = function() {
1652     element = jqLite(element);
1653
1654     if (element.injector()) {
1655       var tag = (element[0] === document) ? 'document' : startingTag(element);
1656       //Encode angle brackets to prevent input from being sanitized to empty string #8683
1657       throw ngMinErr(
1658           'btstrpd',
1659           "App Already Bootstrapped with this Element '{0}'",
1660           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1661     }
1662
1663     modules = modules || [];
1664     modules.unshift(['$provide', function($provide) {
1665       $provide.value('$rootElement', element);
1666     }]);
1667
1668     if (config.debugInfoEnabled) {
1669       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1670       modules.push(['$compileProvider', function($compileProvider) {
1671         $compileProvider.debugInfoEnabled(true);
1672       }]);
1673     }
1674
1675     modules.unshift('ng');
1676     var injector = createInjector(modules, config.strictDi);
1677     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1678        function bootstrapApply(scope, element, compile, injector) {
1679         scope.$apply(function() {
1680           element.data('$injector', injector);
1681           compile(element)(scope);
1682         });
1683       }]
1684     );
1685     return injector;
1686   };
1687
1688   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1689   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1690
1691   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1692     config.debugInfoEnabled = true;
1693     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1694   }
1695
1696   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1697     return doBootstrap();
1698   }
1699
1700   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1701   angular.resumeBootstrap = function(extraModules) {
1702     forEach(extraModules, function(module) {
1703       modules.push(module);
1704     });
1705     return doBootstrap();
1706   };
1707
1708   if (isFunction(angular.resumeDeferredBootstrap)) {
1709     angular.resumeDeferredBootstrap();
1710   }
1711 }
1712
1713 /**
1714  * @ngdoc function
1715  * @name angular.reloadWithDebugInfo
1716  * @module ng
1717  * @description
1718  * Use this function to reload the current application with debug information turned on.
1719  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1720  *
1721  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1722  */
1723 function reloadWithDebugInfo() {
1724   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1725   window.location.reload();
1726 }
1727
1728 /**
1729  * @name angular.getTestability
1730  * @module ng
1731  * @description
1732  * Get the testability service for the instance of Angular on the given
1733  * element.
1734  * @param {DOMElement} element DOM element which is the root of angular application.
1735  */
1736 function getTestability(rootElement) {
1737   var injector = angular.element(rootElement).injector();
1738   if (!injector) {
1739     throw ngMinErr('test',
1740       'no injector found for element argument to getTestability');
1741   }
1742   return injector.get('$$testability');
1743 }
1744
1745 var SNAKE_CASE_REGEXP = /[A-Z]/g;
1746 function snake_case(name, separator) {
1747   separator = separator || '_';
1748   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1749     return (pos ? separator : '') + letter.toLowerCase();
1750   });
1751 }
1752
1753 var bindJQueryFired = false;
1754 var skipDestroyOnNextJQueryCleanData;
1755 function bindJQuery() {
1756   var originalCleanData;
1757
1758   if (bindJQueryFired) {
1759     return;
1760   }
1761
1762   // bind to jQuery if present;
1763   var jqName = jq();
1764   jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
1765            !jqName             ? undefined     :   // use jqLite
1766                                  window[jqName];   // use jQuery specified by `ngJq`
1767
1768   // Use jQuery if it exists with proper functionality, otherwise default to us.
1769   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1770   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1771   // versions. It will not work for sure with jQuery <1.7, though.
1772   if (jQuery && jQuery.fn.on) {
1773     jqLite = jQuery;
1774     extend(jQuery.fn, {
1775       scope: JQLitePrototype.scope,
1776       isolateScope: JQLitePrototype.isolateScope,
1777       controller: JQLitePrototype.controller,
1778       injector: JQLitePrototype.injector,
1779       inheritedData: JQLitePrototype.inheritedData
1780     });
1781
1782     // All nodes removed from the DOM via various jQuery APIs like .remove()
1783     // are passed through jQuery.cleanData. Monkey-patch this method to fire
1784     // the $destroy event on all removed nodes.
1785     originalCleanData = jQuery.cleanData;
1786     jQuery.cleanData = function(elems) {
1787       var events;
1788       if (!skipDestroyOnNextJQueryCleanData) {
1789         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1790           events = jQuery._data(elem, "events");
1791           if (events && events.$destroy) {
1792             jQuery(elem).triggerHandler('$destroy');
1793           }
1794         }
1795       } else {
1796         skipDestroyOnNextJQueryCleanData = false;
1797       }
1798       originalCleanData(elems);
1799     };
1800   } else {
1801     jqLite = JQLite;
1802   }
1803
1804   angular.element = jqLite;
1805
1806   // Prevent double-proxying.
1807   bindJQueryFired = true;
1808 }
1809
1810 /**
1811  * throw error if the argument is falsy.
1812  */
1813 function assertArg(arg, name, reason) {
1814   if (!arg) {
1815     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1816   }
1817   return arg;
1818 }
1819
1820 function assertArgFn(arg, name, acceptArrayAnnotation) {
1821   if (acceptArrayAnnotation && isArray(arg)) {
1822       arg = arg[arg.length - 1];
1823   }
1824
1825   assertArg(isFunction(arg), name, 'not a function, got ' +
1826       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1827   return arg;
1828 }
1829
1830 /**
1831  * throw error if the name given is hasOwnProperty
1832  * @param  {String} name    the name to test
1833  * @param  {String} context the context in which the name is used, such as module or directive
1834  */
1835 function assertNotHasOwnProperty(name, context) {
1836   if (name === 'hasOwnProperty') {
1837     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1838   }
1839 }
1840
1841 /**
1842  * Return the value accessible from the object by path. Any undefined traversals are ignored
1843  * @param {Object} obj starting object
1844  * @param {String} path path to traverse
1845  * @param {boolean} [bindFnToScope=true]
1846  * @returns {Object} value as accessible by path
1847  */
1848 //TODO(misko): this function needs to be removed
1849 function getter(obj, path, bindFnToScope) {
1850   if (!path) return obj;
1851   var keys = path.split('.');
1852   var key;
1853   var lastInstance = obj;
1854   var len = keys.length;
1855
1856   for (var i = 0; i < len; i++) {
1857     key = keys[i];
1858     if (obj) {
1859       obj = (lastInstance = obj)[key];
1860     }
1861   }
1862   if (!bindFnToScope && isFunction(obj)) {
1863     return bind(lastInstance, obj);
1864   }
1865   return obj;
1866 }
1867
1868 /**
1869  * Return the DOM siblings between the first and last node in the given array.
1870  * @param {Array} array like object
1871  * @returns {Array} the inputted object or a jqLite collection containing the nodes
1872  */
1873 function getBlockNodes(nodes) {
1874   // TODO(perf): update `nodes` instead of creating a new object?
1875   var node = nodes[0];
1876   var endNode = nodes[nodes.length - 1];
1877   var blockNodes;
1878
1879   for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
1880     if (blockNodes || nodes[i] !== node) {
1881       if (!blockNodes) {
1882         blockNodes = jqLite(slice.call(nodes, 0, i));
1883       }
1884       blockNodes.push(node);
1885     }
1886   }
1887
1888   return blockNodes || nodes;
1889 }
1890
1891
1892 /**
1893  * Creates a new object without a prototype. This object is useful for lookup without having to
1894  * guard against prototypically inherited properties via hasOwnProperty.
1895  *
1896  * Related micro-benchmarks:
1897  * - http://jsperf.com/object-create2
1898  * - http://jsperf.com/proto-map-lookup/2
1899  * - http://jsperf.com/for-in-vs-object-keys2
1900  *
1901  * @returns {Object}
1902  */
1903 function createMap() {
1904   return Object.create(null);
1905 }
1906
1907 var NODE_TYPE_ELEMENT = 1;
1908 var NODE_TYPE_ATTRIBUTE = 2;
1909 var NODE_TYPE_TEXT = 3;
1910 var NODE_TYPE_COMMENT = 8;
1911 var NODE_TYPE_DOCUMENT = 9;
1912 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1913
1914 /**
1915  * @ngdoc type
1916  * @name angular.Module
1917  * @module ng
1918  * @description
1919  *
1920  * Interface for configuring angular {@link angular.module modules}.
1921  */
1922
1923 function setupModuleLoader(window) {
1924
1925   var $injectorMinErr = minErr('$injector');
1926   var ngMinErr = minErr('ng');
1927
1928   function ensure(obj, name, factory) {
1929     return obj[name] || (obj[name] = factory());
1930   }
1931
1932   var angular = ensure(window, 'angular', Object);
1933
1934   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1935   angular.$$minErr = angular.$$minErr || minErr;
1936
1937   return ensure(angular, 'module', function() {
1938     /** @type {Object.<string, angular.Module>} */
1939     var modules = {};
1940
1941     /**
1942      * @ngdoc function
1943      * @name angular.module
1944      * @module ng
1945      * @description
1946      *
1947      * The `angular.module` is a global place for creating, registering and retrieving Angular
1948      * modules.
1949      * All modules (angular core or 3rd party) that should be available to an application must be
1950      * registered using this mechanism.
1951      *
1952      * Passing one argument retrieves an existing {@link angular.Module},
1953      * whereas passing more than one argument creates a new {@link angular.Module}
1954      *
1955      *
1956      * # Module
1957      *
1958      * A module is a collection of services, directives, controllers, filters, and configuration information.
1959      * `angular.module` is used to configure the {@link auto.$injector $injector}.
1960      *
1961      * ```js
1962      * // Create a new module
1963      * var myModule = angular.module('myModule', []);
1964      *
1965      * // register a new service
1966      * myModule.value('appName', 'MyCoolApp');
1967      *
1968      * // configure existing services inside initialization blocks.
1969      * myModule.config(['$locationProvider', function($locationProvider) {
1970      *   // Configure existing providers
1971      *   $locationProvider.hashPrefix('!');
1972      * }]);
1973      * ```
1974      *
1975      * Then you can create an injector and load your modules like this:
1976      *
1977      * ```js
1978      * var injector = angular.injector(['ng', 'myModule'])
1979      * ```
1980      *
1981      * However it's more likely that you'll just use
1982      * {@link ng.directive:ngApp ngApp} or
1983      * {@link angular.bootstrap} to simplify this process for you.
1984      *
1985      * @param {!string} name The name of the module to create or retrieve.
1986      * @param {!Array.<string>=} requires If specified then new module is being created. If
1987      *        unspecified then the module is being retrieved for further configuration.
1988      * @param {Function=} configFn Optional configuration function for the module. Same as
1989      *        {@link angular.Module#config Module#config()}.
1990      * @returns {module} new module with the {@link angular.Module} api.
1991      */
1992     return function module(name, requires, configFn) {
1993       var assertNotHasOwnProperty = function(name, context) {
1994         if (name === 'hasOwnProperty') {
1995           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1996         }
1997       };
1998
1999       assertNotHasOwnProperty(name, 'module');
2000       if (requires && modules.hasOwnProperty(name)) {
2001         modules[name] = null;
2002       }
2003       return ensure(modules, name, function() {
2004         if (!requires) {
2005           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
2006              "the module name or forgot to load it. If registering a module ensure that you " +
2007              "specify the dependencies as the second argument.", name);
2008         }
2009
2010         /** @type {!Array.<Array.<*>>} */
2011         var invokeQueue = [];
2012
2013         /** @type {!Array.<Function>} */
2014         var configBlocks = [];
2015
2016         /** @type {!Array.<Function>} */
2017         var runBlocks = [];
2018
2019         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2020
2021         /** @type {angular.Module} */
2022         var moduleInstance = {
2023           // Private state
2024           _invokeQueue: invokeQueue,
2025           _configBlocks: configBlocks,
2026           _runBlocks: runBlocks,
2027
2028           /**
2029            * @ngdoc property
2030            * @name angular.Module#requires
2031            * @module ng
2032            *
2033            * @description
2034            * Holds the list of modules which the injector will load before the current module is
2035            * loaded.
2036            */
2037           requires: requires,
2038
2039           /**
2040            * @ngdoc property
2041            * @name angular.Module#name
2042            * @module ng
2043            *
2044            * @description
2045            * Name of the module.
2046            */
2047           name: name,
2048
2049
2050           /**
2051            * @ngdoc method
2052            * @name angular.Module#provider
2053            * @module ng
2054            * @param {string} name service name
2055            * @param {Function} providerType Construction function for creating new instance of the
2056            *                                service.
2057            * @description
2058            * See {@link auto.$provide#provider $provide.provider()}.
2059            */
2060           provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2061
2062           /**
2063            * @ngdoc method
2064            * @name angular.Module#factory
2065            * @module ng
2066            * @param {string} name service name
2067            * @param {Function} providerFunction Function for creating new instance of the service.
2068            * @description
2069            * See {@link auto.$provide#factory $provide.factory()}.
2070            */
2071           factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2072
2073           /**
2074            * @ngdoc method
2075            * @name angular.Module#service
2076            * @module ng
2077            * @param {string} name service name
2078            * @param {Function} constructor A constructor function that will be instantiated.
2079            * @description
2080            * See {@link auto.$provide#service $provide.service()}.
2081            */
2082           service: invokeLaterAndSetModuleName('$provide', 'service'),
2083
2084           /**
2085            * @ngdoc method
2086            * @name angular.Module#value
2087            * @module ng
2088            * @param {string} name service name
2089            * @param {*} object Service instance object.
2090            * @description
2091            * See {@link auto.$provide#value $provide.value()}.
2092            */
2093           value: invokeLater('$provide', 'value'),
2094
2095           /**
2096            * @ngdoc method
2097            * @name angular.Module#constant
2098            * @module ng
2099            * @param {string} name constant name
2100            * @param {*} object Constant value.
2101            * @description
2102            * Because the constants are fixed, they get applied before other provide methods.
2103            * See {@link auto.$provide#constant $provide.constant()}.
2104            */
2105           constant: invokeLater('$provide', 'constant', 'unshift'),
2106
2107            /**
2108            * @ngdoc method
2109            * @name angular.Module#decorator
2110            * @module ng
2111            * @param {string} The name of the service to decorate.
2112            * @param {Function} This function will be invoked when the service needs to be
2113            *                                    instantiated and should return the decorated service instance.
2114            * @description
2115            * See {@link auto.$provide#decorator $provide.decorator()}.
2116            */
2117           decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2118
2119           /**
2120            * @ngdoc method
2121            * @name angular.Module#animation
2122            * @module ng
2123            * @param {string} name animation name
2124            * @param {Function} animationFactory Factory function for creating new instance of an
2125            *                                    animation.
2126            * @description
2127            *
2128            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2129            *
2130            *
2131            * Defines an animation hook that can be later used with
2132            * {@link $animate $animate} service and directives that use this service.
2133            *
2134            * ```js
2135            * module.animation('.animation-name', function($inject1, $inject2) {
2136            *   return {
2137            *     eventName : function(element, done) {
2138            *       //code to run the animation
2139            *       //once complete, then run done()
2140            *       return function cancellationFunction(element) {
2141            *         //code to cancel the animation
2142            *       }
2143            *     }
2144            *   }
2145            * })
2146            * ```
2147            *
2148            * See {@link ng.$animateProvider#register $animateProvider.register()} and
2149            * {@link ngAnimate ngAnimate module} for more information.
2150            */
2151           animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2152
2153           /**
2154            * @ngdoc method
2155            * @name angular.Module#filter
2156            * @module ng
2157            * @param {string} name Filter name - this must be a valid angular expression identifier
2158            * @param {Function} filterFactory Factory function for creating new instance of filter.
2159            * @description
2160            * See {@link ng.$filterProvider#register $filterProvider.register()}.
2161            *
2162            * <div class="alert alert-warning">
2163            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2164            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2165            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2166            * (`myapp_subsection_filterx`).
2167            * </div>
2168            */
2169           filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2170
2171           /**
2172            * @ngdoc method
2173            * @name angular.Module#controller
2174            * @module ng
2175            * @param {string|Object} name Controller name, or an object map of controllers where the
2176            *    keys are the names and the values are the constructors.
2177            * @param {Function} constructor Controller constructor function.
2178            * @description
2179            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2180            */
2181           controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2182
2183           /**
2184            * @ngdoc method
2185            * @name angular.Module#directive
2186            * @module ng
2187            * @param {string|Object} name Directive name, or an object map of directives where the
2188            *    keys are the names and the values are the factories.
2189            * @param {Function} directiveFactory Factory function for creating new instance of
2190            * directives.
2191            * @description
2192            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2193            */
2194           directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2195
2196           /**
2197            * @ngdoc method
2198            * @name angular.Module#config
2199            * @module ng
2200            * @param {Function} configFn Execute this function on module load. Useful for service
2201            *    configuration.
2202            * @description
2203            * Use this method to register work which needs to be performed on module loading.
2204            * For more about how to configure services, see
2205            * {@link providers#provider-recipe Provider Recipe}.
2206            */
2207           config: config,
2208
2209           /**
2210            * @ngdoc method
2211            * @name angular.Module#run
2212            * @module ng
2213            * @param {Function} initializationFn Execute this function after injector creation.
2214            *    Useful for application initialization.
2215            * @description
2216            * Use this method to register work which should be performed when the injector is done
2217            * loading all modules.
2218            */
2219           run: function(block) {
2220             runBlocks.push(block);
2221             return this;
2222           }
2223         };
2224
2225         if (configFn) {
2226           config(configFn);
2227         }
2228
2229         return moduleInstance;
2230
2231         /**
2232          * @param {string} provider
2233          * @param {string} method
2234          * @param {String=} insertMethod
2235          * @returns {angular.Module}
2236          */
2237         function invokeLater(provider, method, insertMethod, queue) {
2238           if (!queue) queue = invokeQueue;
2239           return function() {
2240             queue[insertMethod || 'push']([provider, method, arguments]);
2241             return moduleInstance;
2242           };
2243         }
2244
2245         /**
2246          * @param {string} provider
2247          * @param {string} method
2248          * @returns {angular.Module}
2249          */
2250         function invokeLaterAndSetModuleName(provider, method) {
2251           return function(recipeName, factoryFunction) {
2252             if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2253             invokeQueue.push([provider, method, arguments]);
2254             return moduleInstance;
2255           };
2256         }
2257       });
2258     };
2259   });
2260
2261 }
2262
2263 /* global: toDebugString: true */
2264
2265 function serializeObject(obj) {
2266   var seen = [];
2267
2268   return JSON.stringify(obj, function(key, val) {
2269     val = toJsonReplacer(key, val);
2270     if (isObject(val)) {
2271
2272       if (seen.indexOf(val) >= 0) return '...';
2273
2274       seen.push(val);
2275     }
2276     return val;
2277   });
2278 }
2279
2280 function toDebugString(obj) {
2281   if (typeof obj === 'function') {
2282     return obj.toString().replace(/ \{[\s\S]*$/, '');
2283   } else if (isUndefined(obj)) {
2284     return 'undefined';
2285   } else if (typeof obj !== 'string') {
2286     return serializeObject(obj);
2287   }
2288   return obj;
2289 }
2290
2291 /* global angularModule: true,
2292   version: true,
2293
2294   $CompileProvider,
2295
2296   htmlAnchorDirective,
2297   inputDirective,
2298   inputDirective,
2299   formDirective,
2300   scriptDirective,
2301   selectDirective,
2302   styleDirective,
2303   optionDirective,
2304   ngBindDirective,
2305   ngBindHtmlDirective,
2306   ngBindTemplateDirective,
2307   ngClassDirective,
2308   ngClassEvenDirective,
2309   ngClassOddDirective,
2310   ngCloakDirective,
2311   ngControllerDirective,
2312   ngFormDirective,
2313   ngHideDirective,
2314   ngIfDirective,
2315   ngIncludeDirective,
2316   ngIncludeFillContentDirective,
2317   ngInitDirective,
2318   ngNonBindableDirective,
2319   ngPluralizeDirective,
2320   ngRepeatDirective,
2321   ngShowDirective,
2322   ngStyleDirective,
2323   ngSwitchDirective,
2324   ngSwitchWhenDirective,
2325   ngSwitchDefaultDirective,
2326   ngOptionsDirective,
2327   ngTranscludeDirective,
2328   ngModelDirective,
2329   ngListDirective,
2330   ngChangeDirective,
2331   patternDirective,
2332   patternDirective,
2333   requiredDirective,
2334   requiredDirective,
2335   minlengthDirective,
2336   minlengthDirective,
2337   maxlengthDirective,
2338   maxlengthDirective,
2339   ngValueDirective,
2340   ngModelOptionsDirective,
2341   ngAttributeAliasDirectives,
2342   ngEventDirectives,
2343
2344   $AnchorScrollProvider,
2345   $AnimateProvider,
2346   $CoreAnimateCssProvider,
2347   $$CoreAnimateQueueProvider,
2348   $$CoreAnimateRunnerProvider,
2349   $BrowserProvider,
2350   $CacheFactoryProvider,
2351   $ControllerProvider,
2352   $DocumentProvider,
2353   $ExceptionHandlerProvider,
2354   $FilterProvider,
2355   $$ForceReflowProvider,
2356   $InterpolateProvider,
2357   $IntervalProvider,
2358   $$HashMapProvider,
2359   $HttpProvider,
2360   $HttpParamSerializerProvider,
2361   $HttpParamSerializerJQLikeProvider,
2362   $HttpBackendProvider,
2363   $xhrFactoryProvider,
2364   $LocationProvider,
2365   $LogProvider,
2366   $ParseProvider,
2367   $RootScopeProvider,
2368   $QProvider,
2369   $$QProvider,
2370   $$SanitizeUriProvider,
2371   $SceProvider,
2372   $SceDelegateProvider,
2373   $SnifferProvider,
2374   $TemplateCacheProvider,
2375   $TemplateRequestProvider,
2376   $$TestabilityProvider,
2377   $TimeoutProvider,
2378   $$RAFProvider,
2379   $WindowProvider,
2380   $$jqLiteProvider,
2381   $$CookieReaderProvider
2382 */
2383
2384
2385 /**
2386  * @ngdoc object
2387  * @name angular.version
2388  * @module ng
2389  * @description
2390  * An object that contains information about the current AngularJS version.
2391  *
2392  * This object has the following properties:
2393  *
2394  * - `full` – `{string}` – Full version string, such as "0.9.18".
2395  * - `major` – `{number}` – Major version number, such as "0".
2396  * - `minor` – `{number}` – Minor version number, such as "9".
2397  * - `dot` – `{number}` – Dot version number, such as "18".
2398  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2399  */
2400 var version = {
2401   full: '1.4.8',    // all of these placeholder strings will be replaced by grunt's
2402   major: 1,    // package task
2403   minor: 4,
2404   dot: 8,
2405   codeName: 'ice-manipulation'
2406 };
2407
2408
2409 function publishExternalAPI(angular) {
2410   extend(angular, {
2411     'bootstrap': bootstrap,
2412     'copy': copy,
2413     'extend': extend,
2414     'merge': merge,
2415     'equals': equals,
2416     'element': jqLite,
2417     'forEach': forEach,
2418     'injector': createInjector,
2419     'noop': noop,
2420     'bind': bind,
2421     'toJson': toJson,
2422     'fromJson': fromJson,
2423     'identity': identity,
2424     'isUndefined': isUndefined,
2425     'isDefined': isDefined,
2426     'isString': isString,
2427     'isFunction': isFunction,
2428     'isObject': isObject,
2429     'isNumber': isNumber,
2430     'isElement': isElement,
2431     'isArray': isArray,
2432     'version': version,
2433     'isDate': isDate,
2434     'lowercase': lowercase,
2435     'uppercase': uppercase,
2436     'callbacks': {counter: 0},
2437     'getTestability': getTestability,
2438     '$$minErr': minErr,
2439     '$$csp': csp,
2440     'reloadWithDebugInfo': reloadWithDebugInfo
2441   });
2442
2443   angularModule = setupModuleLoader(window);
2444
2445   angularModule('ng', ['ngLocale'], ['$provide',
2446     function ngModule($provide) {
2447       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2448       $provide.provider({
2449         $$sanitizeUri: $$SanitizeUriProvider
2450       });
2451       $provide.provider('$compile', $CompileProvider).
2452         directive({
2453             a: htmlAnchorDirective,
2454             input: inputDirective,
2455             textarea: inputDirective,
2456             form: formDirective,
2457             script: scriptDirective,
2458             select: selectDirective,
2459             style: styleDirective,
2460             option: optionDirective,
2461             ngBind: ngBindDirective,
2462             ngBindHtml: ngBindHtmlDirective,
2463             ngBindTemplate: ngBindTemplateDirective,
2464             ngClass: ngClassDirective,
2465             ngClassEven: ngClassEvenDirective,
2466             ngClassOdd: ngClassOddDirective,
2467             ngCloak: ngCloakDirective,
2468             ngController: ngControllerDirective,
2469             ngForm: ngFormDirective,
2470             ngHide: ngHideDirective,
2471             ngIf: ngIfDirective,
2472             ngInclude: ngIncludeDirective,
2473             ngInit: ngInitDirective,
2474             ngNonBindable: ngNonBindableDirective,
2475             ngPluralize: ngPluralizeDirective,
2476             ngRepeat: ngRepeatDirective,
2477             ngShow: ngShowDirective,
2478             ngStyle: ngStyleDirective,
2479             ngSwitch: ngSwitchDirective,
2480             ngSwitchWhen: ngSwitchWhenDirective,
2481             ngSwitchDefault: ngSwitchDefaultDirective,
2482             ngOptions: ngOptionsDirective,
2483             ngTransclude: ngTranscludeDirective,
2484             ngModel: ngModelDirective,
2485             ngList: ngListDirective,
2486             ngChange: ngChangeDirective,
2487             pattern: patternDirective,
2488             ngPattern: patternDirective,
2489             required: requiredDirective,
2490             ngRequired: requiredDirective,
2491             minlength: minlengthDirective,
2492             ngMinlength: minlengthDirective,
2493             maxlength: maxlengthDirective,
2494             ngMaxlength: maxlengthDirective,
2495             ngValue: ngValueDirective,
2496             ngModelOptions: ngModelOptionsDirective
2497         }).
2498         directive({
2499           ngInclude: ngIncludeFillContentDirective
2500         }).
2501         directive(ngAttributeAliasDirectives).
2502         directive(ngEventDirectives);
2503       $provide.provider({
2504         $anchorScroll: $AnchorScrollProvider,
2505         $animate: $AnimateProvider,
2506         $animateCss: $CoreAnimateCssProvider,
2507         $$animateQueue: $$CoreAnimateQueueProvider,
2508         $$AnimateRunner: $$CoreAnimateRunnerProvider,
2509         $browser: $BrowserProvider,
2510         $cacheFactory: $CacheFactoryProvider,
2511         $controller: $ControllerProvider,
2512         $document: $DocumentProvider,
2513         $exceptionHandler: $ExceptionHandlerProvider,
2514         $filter: $FilterProvider,
2515         $$forceReflow: $$ForceReflowProvider,
2516         $interpolate: $InterpolateProvider,
2517         $interval: $IntervalProvider,
2518         $http: $HttpProvider,
2519         $httpParamSerializer: $HttpParamSerializerProvider,
2520         $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2521         $httpBackend: $HttpBackendProvider,
2522         $xhrFactory: $xhrFactoryProvider,
2523         $location: $LocationProvider,
2524         $log: $LogProvider,
2525         $parse: $ParseProvider,
2526         $rootScope: $RootScopeProvider,
2527         $q: $QProvider,
2528         $$q: $$QProvider,
2529         $sce: $SceProvider,
2530         $sceDelegate: $SceDelegateProvider,
2531         $sniffer: $SnifferProvider,
2532         $templateCache: $TemplateCacheProvider,
2533         $templateRequest: $TemplateRequestProvider,
2534         $$testability: $$TestabilityProvider,
2535         $timeout: $TimeoutProvider,
2536         $window: $WindowProvider,
2537         $$rAF: $$RAFProvider,
2538         $$jqLite: $$jqLiteProvider,
2539         $$HashMap: $$HashMapProvider,
2540         $$cookieReader: $$CookieReaderProvider
2541       });
2542     }
2543   ]);
2544 }
2545
2546 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2547  *     Any commits to this file should be reviewed with security in mind.  *
2548  *   Changes to this file can potentially create security vulnerabilities. *
2549  *          An approval from 2 Core members with history of modifying      *
2550  *                         this file is required.                          *
2551  *                                                                         *
2552  *  Does the change somehow allow for arbitrary javascript to be executed? *
2553  *    Or allows for someone to change the prototype of built-in objects?   *
2554  *     Or gives undesired access to variables likes document or window?    *
2555  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2556
2557 /* global JQLitePrototype: true,
2558   addEventListenerFn: true,
2559   removeEventListenerFn: true,
2560   BOOLEAN_ATTR: true,
2561   ALIASED_ATTR: true,
2562 */
2563
2564 //////////////////////////////////
2565 //JQLite
2566 //////////////////////////////////
2567
2568 /**
2569  * @ngdoc function
2570  * @name angular.element
2571  * @module ng
2572  * @kind function
2573  *
2574  * @description
2575  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2576  *
2577  * If jQuery is available, `angular.element` is an alias for the
2578  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2579  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2580  *
2581  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2582  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2583  * commonly needed functionality with the goal of having a very small footprint.</div>
2584  *
2585  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2586  *
2587  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2588  * jqLite; they are never raw DOM references.</div>
2589  *
2590  * ## Angular's jqLite
2591  * jqLite provides only the following jQuery methods:
2592  *
2593  * - [`addClass()`](http://api.jquery.com/addClass/)
2594  * - [`after()`](http://api.jquery.com/after/)
2595  * - [`append()`](http://api.jquery.com/append/)
2596  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2597  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2598  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2599  * - [`clone()`](http://api.jquery.com/clone/)
2600  * - [`contents()`](http://api.jquery.com/contents/)
2601  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
2602  * - [`data()`](http://api.jquery.com/data/)
2603  * - [`detach()`](http://api.jquery.com/detach/)
2604  * - [`empty()`](http://api.jquery.com/empty/)
2605  * - [`eq()`](http://api.jquery.com/eq/)
2606  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2607  * - [`hasClass()`](http://api.jquery.com/hasClass/)
2608  * - [`html()`](http://api.jquery.com/html/)
2609  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2610  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2611  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2612  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2613  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2614  * - [`prepend()`](http://api.jquery.com/prepend/)
2615  * - [`prop()`](http://api.jquery.com/prop/)
2616  * - [`ready()`](http://api.jquery.com/ready/)
2617  * - [`remove()`](http://api.jquery.com/remove/)
2618  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2619  * - [`removeClass()`](http://api.jquery.com/removeClass/)
2620  * - [`removeData()`](http://api.jquery.com/removeData/)
2621  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2622  * - [`text()`](http://api.jquery.com/text/)
2623  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2624  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2625  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2626  * - [`val()`](http://api.jquery.com/val/)
2627  * - [`wrap()`](http://api.jquery.com/wrap/)
2628  *
2629  * ## jQuery/jqLite Extras
2630  * Angular also provides the following additional methods and events to both jQuery and jqLite:
2631  *
2632  * ### Events
2633  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2634  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2635  *    element before it is removed.
2636  *
2637  * ### Methods
2638  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2639  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2640  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2641  *   `'ngModel'`).
2642  * - `injector()` - retrieves the injector of the current element or its parent.
2643  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2644  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2645  *   be enabled.
2646  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2647  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2648  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2649  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2650  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2651  *   parent element is reached.
2652  *
2653  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2654  * @returns {Object} jQuery object.
2655  */
2656
2657 JQLite.expando = 'ng339';
2658
2659 var jqCache = JQLite.cache = {},
2660     jqId = 1,
2661     addEventListenerFn = function(element, type, fn) {
2662       element.addEventListener(type, fn, false);
2663     },
2664     removeEventListenerFn = function(element, type, fn) {
2665       element.removeEventListener(type, fn, false);
2666     };
2667
2668 /*
2669  * !!! This is an undocumented "private" function !!!
2670  */
2671 JQLite._data = function(node) {
2672   //jQuery always returns an object on cache miss
2673   return this.cache[node[this.expando]] || {};
2674 };
2675
2676 function jqNextId() { return ++jqId; }
2677
2678
2679 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2680 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2681 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2682 var jqLiteMinErr = minErr('jqLite');
2683
2684 /**
2685  * Converts snake_case to camelCase.
2686  * Also there is special case for Moz prefix starting with upper case letter.
2687  * @param name Name to normalize
2688  */
2689 function camelCase(name) {
2690   return name.
2691     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2692       return offset ? letter.toUpperCase() : letter;
2693     }).
2694     replace(MOZ_HACK_REGEXP, 'Moz$1');
2695 }
2696
2697 var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2698 var HTML_REGEXP = /<|&#?\w+;/;
2699 var TAG_NAME_REGEXP = /<([\w:-]+)/;
2700 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2701
2702 var wrapMap = {
2703   'option': [1, '<select multiple="multiple">', '</select>'],
2704
2705   'thead': [1, '<table>', '</table>'],
2706   'col': [2, '<table><colgroup>', '</colgroup></table>'],
2707   'tr': [2, '<table><tbody>', '</tbody></table>'],
2708   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2709   '_default': [0, "", ""]
2710 };
2711
2712 wrapMap.optgroup = wrapMap.option;
2713 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2714 wrapMap.th = wrapMap.td;
2715
2716
2717 function jqLiteIsTextNode(html) {
2718   return !HTML_REGEXP.test(html);
2719 }
2720
2721 function jqLiteAcceptsData(node) {
2722   // The window object can accept data but has no nodeType
2723   // Otherwise we are only interested in elements (1) and documents (9)
2724   var nodeType = node.nodeType;
2725   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2726 }
2727
2728 function jqLiteHasData(node) {
2729   for (var key in jqCache[node.ng339]) {
2730     return true;
2731   }
2732   return false;
2733 }
2734
2735 function jqLiteBuildFragment(html, context) {
2736   var tmp, tag, wrap,
2737       fragment = context.createDocumentFragment(),
2738       nodes = [], i;
2739
2740   if (jqLiteIsTextNode(html)) {
2741     // Convert non-html into a text node
2742     nodes.push(context.createTextNode(html));
2743   } else {
2744     // Convert html into DOM nodes
2745     tmp = tmp || fragment.appendChild(context.createElement("div"));
2746     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2747     wrap = wrapMap[tag] || wrapMap._default;
2748     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2749
2750     // Descend through wrappers to the right content
2751     i = wrap[0];
2752     while (i--) {
2753       tmp = tmp.lastChild;
2754     }
2755
2756     nodes = concat(nodes, tmp.childNodes);
2757
2758     tmp = fragment.firstChild;
2759     tmp.textContent = "";
2760   }
2761
2762   // Remove wrapper from fragment
2763   fragment.textContent = "";
2764   fragment.innerHTML = ""; // Clear inner HTML
2765   forEach(nodes, function(node) {
2766     fragment.appendChild(node);
2767   });
2768
2769   return fragment;
2770 }
2771
2772 function jqLiteParseHTML(html, context) {
2773   context = context || document;
2774   var parsed;
2775
2776   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2777     return [context.createElement(parsed[1])];
2778   }
2779
2780   if ((parsed = jqLiteBuildFragment(html, context))) {
2781     return parsed.childNodes;
2782   }
2783
2784   return [];
2785 }
2786
2787
2788 // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2789 var jqLiteContains = Node.prototype.contains || function(arg) {
2790   // jshint bitwise: false
2791   return !!(this.compareDocumentPosition(arg) & 16);
2792   // jshint bitwise: true
2793 };
2794
2795 /////////////////////////////////////////////
2796 function JQLite(element) {
2797   if (element instanceof JQLite) {
2798     return element;
2799   }
2800
2801   var argIsString;
2802
2803   if (isString(element)) {
2804     element = trim(element);
2805     argIsString = true;
2806   }
2807   if (!(this instanceof JQLite)) {
2808     if (argIsString && element.charAt(0) != '<') {
2809       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2810     }
2811     return new JQLite(element);
2812   }
2813
2814   if (argIsString) {
2815     jqLiteAddNodes(this, jqLiteParseHTML(element));
2816   } else {
2817     jqLiteAddNodes(this, element);
2818   }
2819 }
2820
2821 function jqLiteClone(element) {
2822   return element.cloneNode(true);
2823 }
2824
2825 function jqLiteDealoc(element, onlyDescendants) {
2826   if (!onlyDescendants) jqLiteRemoveData(element);
2827
2828   if (element.querySelectorAll) {
2829     var descendants = element.querySelectorAll('*');
2830     for (var i = 0, l = descendants.length; i < l; i++) {
2831       jqLiteRemoveData(descendants[i]);
2832     }
2833   }
2834 }
2835
2836 function jqLiteOff(element, type, fn, unsupported) {
2837   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2838
2839   var expandoStore = jqLiteExpandoStore(element);
2840   var events = expandoStore && expandoStore.events;
2841   var handle = expandoStore && expandoStore.handle;
2842
2843   if (!handle) return; //no listeners registered
2844
2845   if (!type) {
2846     for (type in events) {
2847       if (type !== '$destroy') {
2848         removeEventListenerFn(element, type, handle);
2849       }
2850       delete events[type];
2851     }
2852   } else {
2853
2854     var removeHandler = function(type) {
2855       var listenerFns = events[type];
2856       if (isDefined(fn)) {
2857         arrayRemove(listenerFns || [], fn);
2858       }
2859       if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
2860         removeEventListenerFn(element, type, handle);
2861         delete events[type];
2862       }
2863     };
2864
2865     forEach(type.split(' '), function(type) {
2866       removeHandler(type);
2867       if (MOUSE_EVENT_MAP[type]) {
2868         removeHandler(MOUSE_EVENT_MAP[type]);
2869       }
2870     });
2871   }
2872 }
2873
2874 function jqLiteRemoveData(element, name) {
2875   var expandoId = element.ng339;
2876   var expandoStore = expandoId && jqCache[expandoId];
2877
2878   if (expandoStore) {
2879     if (name) {
2880       delete expandoStore.data[name];
2881       return;
2882     }
2883
2884     if (expandoStore.handle) {
2885       if (expandoStore.events.$destroy) {
2886         expandoStore.handle({}, '$destroy');
2887       }
2888       jqLiteOff(element);
2889     }
2890     delete jqCache[expandoId];
2891     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2892   }
2893 }
2894
2895
2896 function jqLiteExpandoStore(element, createIfNecessary) {
2897   var expandoId = element.ng339,
2898       expandoStore = expandoId && jqCache[expandoId];
2899
2900   if (createIfNecessary && !expandoStore) {
2901     element.ng339 = expandoId = jqNextId();
2902     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2903   }
2904
2905   return expandoStore;
2906 }
2907
2908
2909 function jqLiteData(element, key, value) {
2910   if (jqLiteAcceptsData(element)) {
2911
2912     var isSimpleSetter = isDefined(value);
2913     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2914     var massGetter = !key;
2915     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2916     var data = expandoStore && expandoStore.data;
2917
2918     if (isSimpleSetter) { // data('key', value)
2919       data[key] = value;
2920     } else {
2921       if (massGetter) {  // data()
2922         return data;
2923       } else {
2924         if (isSimpleGetter) { // data('key')
2925           // don't force creation of expandoStore if it doesn't exist yet
2926           return data && data[key];
2927         } else { // mass-setter: data({key1: val1, key2: val2})
2928           extend(data, key);
2929         }
2930       }
2931     }
2932   }
2933 }
2934
2935 function jqLiteHasClass(element, selector) {
2936   if (!element.getAttribute) return false;
2937   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2938       indexOf(" " + selector + " ") > -1);
2939 }
2940
2941 function jqLiteRemoveClass(element, cssClasses) {
2942   if (cssClasses && element.setAttribute) {
2943     forEach(cssClasses.split(' '), function(cssClass) {
2944       element.setAttribute('class', trim(
2945           (" " + (element.getAttribute('class') || '') + " ")
2946           .replace(/[\n\t]/g, " ")
2947           .replace(" " + trim(cssClass) + " ", " "))
2948       );
2949     });
2950   }
2951 }
2952
2953 function jqLiteAddClass(element, cssClasses) {
2954   if (cssClasses && element.setAttribute) {
2955     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2956                             .replace(/[\n\t]/g, " ");
2957
2958     forEach(cssClasses.split(' '), function(cssClass) {
2959       cssClass = trim(cssClass);
2960       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2961         existingClasses += cssClass + ' ';
2962       }
2963     });
2964
2965     element.setAttribute('class', trim(existingClasses));
2966   }
2967 }
2968
2969
2970 function jqLiteAddNodes(root, elements) {
2971   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
2972
2973   if (elements) {
2974
2975     // if a Node (the most common case)
2976     if (elements.nodeType) {
2977       root[root.length++] = elements;
2978     } else {
2979       var length = elements.length;
2980
2981       // if an Array or NodeList and not a Window
2982       if (typeof length === 'number' && elements.window !== elements) {
2983         if (length) {
2984           for (var i = 0; i < length; i++) {
2985             root[root.length++] = elements[i];
2986           }
2987         }
2988       } else {
2989         root[root.length++] = elements;
2990       }
2991     }
2992   }
2993 }
2994
2995
2996 function jqLiteController(element, name) {
2997   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
2998 }
2999
3000 function jqLiteInheritedData(element, name, value) {
3001   // if element is the document object work with the html element instead
3002   // this makes $(document).scope() possible
3003   if (element.nodeType == NODE_TYPE_DOCUMENT) {
3004     element = element.documentElement;
3005   }
3006   var names = isArray(name) ? name : [name];
3007
3008   while (element) {
3009     for (var i = 0, ii = names.length; i < ii; i++) {
3010       if (isDefined(value = jqLite.data(element, names[i]))) return value;
3011     }
3012
3013     // If dealing with a document fragment node with a host element, and no parent, use the host
3014     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3015     // to lookup parent controllers.
3016     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3017   }
3018 }
3019
3020 function jqLiteEmpty(element) {
3021   jqLiteDealoc(element, true);
3022   while (element.firstChild) {
3023     element.removeChild(element.firstChild);
3024   }
3025 }
3026
3027 function jqLiteRemove(element, keepData) {
3028   if (!keepData) jqLiteDealoc(element);
3029   var parent = element.parentNode;
3030   if (parent) parent.removeChild(element);
3031 }
3032
3033
3034 function jqLiteDocumentLoaded(action, win) {
3035   win = win || window;
3036   if (win.document.readyState === 'complete') {
3037     // Force the action to be run async for consistent behaviour
3038     // from the action's point of view
3039     // i.e. it will definitely not be in a $apply
3040     win.setTimeout(action);
3041   } else {
3042     // No need to unbind this handler as load is only ever called once
3043     jqLite(win).on('load', action);
3044   }
3045 }
3046
3047 //////////////////////////////////////////
3048 // Functions which are declared directly.
3049 //////////////////////////////////////////
3050 var JQLitePrototype = JQLite.prototype = {
3051   ready: function(fn) {
3052     var fired = false;
3053
3054     function trigger() {
3055       if (fired) return;
3056       fired = true;
3057       fn();
3058     }
3059
3060     // check if document is already loaded
3061     if (document.readyState === 'complete') {
3062       setTimeout(trigger);
3063     } else {
3064       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3065       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3066       // jshint -W064
3067       JQLite(window).on('load', trigger); // fallback to window.onload for others
3068       // jshint +W064
3069     }
3070   },
3071   toString: function() {
3072     var value = [];
3073     forEach(this, function(e) { value.push('' + e);});
3074     return '[' + value.join(', ') + ']';
3075   },
3076
3077   eq: function(index) {
3078       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3079   },
3080
3081   length: 0,
3082   push: push,
3083   sort: [].sort,
3084   splice: [].splice
3085 };
3086
3087 //////////////////////////////////////////
3088 // Functions iterating getter/setters.
3089 // these functions return self on setter and
3090 // value on get.
3091 //////////////////////////////////////////
3092 var BOOLEAN_ATTR = {};
3093 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3094   BOOLEAN_ATTR[lowercase(value)] = value;
3095 });
3096 var BOOLEAN_ELEMENTS = {};
3097 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3098   BOOLEAN_ELEMENTS[value] = true;
3099 });
3100 var ALIASED_ATTR = {
3101   'ngMinlength': 'minlength',
3102   'ngMaxlength': 'maxlength',
3103   'ngMin': 'min',
3104   'ngMax': 'max',
3105   'ngPattern': 'pattern'
3106 };
3107
3108 function getBooleanAttrName(element, name) {
3109   // check dom last since we will most likely fail on name
3110   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3111
3112   // booleanAttr is here twice to minimize DOM access
3113   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3114 }
3115
3116 function getAliasedAttrName(name) {
3117   return ALIASED_ATTR[name];
3118 }
3119
3120 forEach({
3121   data: jqLiteData,
3122   removeData: jqLiteRemoveData,
3123   hasData: jqLiteHasData
3124 }, function(fn, name) {
3125   JQLite[name] = fn;
3126 });
3127
3128 forEach({
3129   data: jqLiteData,
3130   inheritedData: jqLiteInheritedData,
3131
3132   scope: function(element) {
3133     // Can't use jqLiteData here directly so we stay compatible with jQuery!
3134     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3135   },
3136
3137   isolateScope: function(element) {
3138     // Can't use jqLiteData here directly so we stay compatible with jQuery!
3139     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3140   },
3141
3142   controller: jqLiteController,
3143
3144   injector: function(element) {
3145     return jqLiteInheritedData(element, '$injector');
3146   },
3147
3148   removeAttr: function(element, name) {
3149     element.removeAttribute(name);
3150   },
3151
3152   hasClass: jqLiteHasClass,
3153
3154   css: function(element, name, value) {
3155     name = camelCase(name);
3156
3157     if (isDefined(value)) {
3158       element.style[name] = value;
3159     } else {
3160       return element.style[name];
3161     }
3162   },
3163
3164   attr: function(element, name, value) {
3165     var nodeType = element.nodeType;
3166     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3167       return;
3168     }
3169     var lowercasedName = lowercase(name);
3170     if (BOOLEAN_ATTR[lowercasedName]) {
3171       if (isDefined(value)) {
3172         if (!!value) {
3173           element[name] = true;
3174           element.setAttribute(name, lowercasedName);
3175         } else {
3176           element[name] = false;
3177           element.removeAttribute(lowercasedName);
3178         }
3179       } else {
3180         return (element[name] ||
3181                  (element.attributes.getNamedItem(name) || noop).specified)
3182                ? lowercasedName
3183                : undefined;
3184       }
3185     } else if (isDefined(value)) {
3186       element.setAttribute(name, value);
3187     } else if (element.getAttribute) {
3188       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3189       // some elements (e.g. Document) don't have get attribute, so return undefined
3190       var ret = element.getAttribute(name, 2);
3191       // normalize non-existing attributes to undefined (as jQuery)
3192       return ret === null ? undefined : ret;
3193     }
3194   },
3195
3196   prop: function(element, name, value) {
3197     if (isDefined(value)) {
3198       element[name] = value;
3199     } else {
3200       return element[name];
3201     }
3202   },
3203
3204   text: (function() {
3205     getText.$dv = '';
3206     return getText;
3207
3208     function getText(element, value) {
3209       if (isUndefined(value)) {
3210         var nodeType = element.nodeType;
3211         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3212       }
3213       element.textContent = value;
3214     }
3215   })(),
3216
3217   val: function(element, value) {
3218     if (isUndefined(value)) {
3219       if (element.multiple && nodeName_(element) === 'select') {
3220         var result = [];
3221         forEach(element.options, function(option) {
3222           if (option.selected) {
3223             result.push(option.value || option.text);
3224           }
3225         });
3226         return result.length === 0 ? null : result;
3227       }
3228       return element.value;
3229     }
3230     element.value = value;
3231   },
3232
3233   html: function(element, value) {
3234     if (isUndefined(value)) {
3235       return element.innerHTML;
3236     }
3237     jqLiteDealoc(element, true);
3238     element.innerHTML = value;
3239   },
3240
3241   empty: jqLiteEmpty
3242 }, function(fn, name) {
3243   /**
3244    * Properties: writes return selection, reads return first value
3245    */
3246   JQLite.prototype[name] = function(arg1, arg2) {
3247     var i, key;
3248     var nodeCount = this.length;
3249
3250     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3251     // in a way that survives minification.
3252     // jqLiteEmpty takes no arguments but is a setter.
3253     if (fn !== jqLiteEmpty &&
3254         (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3255       if (isObject(arg1)) {
3256
3257         // we are a write, but the object properties are the key/values
3258         for (i = 0; i < nodeCount; i++) {
3259           if (fn === jqLiteData) {
3260             // data() takes the whole object in jQuery
3261             fn(this[i], arg1);
3262           } else {
3263             for (key in arg1) {
3264               fn(this[i], key, arg1[key]);
3265             }
3266           }
3267         }
3268         // return self for chaining
3269         return this;
3270       } else {
3271         // we are a read, so read the first child.
3272         // TODO: do we still need this?
3273         var value = fn.$dv;
3274         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3275         var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3276         for (var j = 0; j < jj; j++) {
3277           var nodeValue = fn(this[j], arg1, arg2);
3278           value = value ? value + nodeValue : nodeValue;
3279         }
3280         return value;
3281       }
3282     } else {
3283       // we are a write, so apply to all children
3284       for (i = 0; i < nodeCount; i++) {
3285         fn(this[i], arg1, arg2);
3286       }
3287       // return self for chaining
3288       return this;
3289     }
3290   };
3291 });
3292
3293 function createEventHandler(element, events) {
3294   var eventHandler = function(event, type) {
3295     // jQuery specific api
3296     event.isDefaultPrevented = function() {
3297       return event.defaultPrevented;
3298     };
3299
3300     var eventFns = events[type || event.type];
3301     var eventFnsLength = eventFns ? eventFns.length : 0;
3302
3303     if (!eventFnsLength) return;
3304
3305     if (isUndefined(event.immediatePropagationStopped)) {
3306       var originalStopImmediatePropagation = event.stopImmediatePropagation;
3307       event.stopImmediatePropagation = function() {
3308         event.immediatePropagationStopped = true;
3309
3310         if (event.stopPropagation) {
3311           event.stopPropagation();
3312         }
3313
3314         if (originalStopImmediatePropagation) {
3315           originalStopImmediatePropagation.call(event);
3316         }
3317       };
3318     }
3319
3320     event.isImmediatePropagationStopped = function() {
3321       return event.immediatePropagationStopped === true;
3322     };
3323
3324     // Some events have special handlers that wrap the real handler
3325     var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3326
3327     // Copy event handlers in case event handlers array is modified during execution.
3328     if ((eventFnsLength > 1)) {
3329       eventFns = shallowCopy(eventFns);
3330     }
3331
3332     for (var i = 0; i < eventFnsLength; i++) {
3333       if (!event.isImmediatePropagationStopped()) {
3334         handlerWrapper(element, event, eventFns[i]);
3335       }
3336     }
3337   };
3338
3339   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3340   //       events on `element`
3341   eventHandler.elem = element;
3342   return eventHandler;
3343 }
3344
3345 function defaultHandlerWrapper(element, event, handler) {
3346   handler.call(element, event);
3347 }
3348
3349 function specialMouseHandlerWrapper(target, event, handler) {
3350   // Refer to jQuery's implementation of mouseenter & mouseleave
3351   // Read about mouseenter and mouseleave:
3352   // http://www.quirksmode.org/js/events_mouse.html#link8
3353   var related = event.relatedTarget;
3354   // For mousenter/leave call the handler if related is outside the target.
3355   // NB: No relatedTarget if the mouse left/entered the browser window
3356   if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3357     handler.call(target, event);
3358   }
3359 }
3360
3361 //////////////////////////////////////////
3362 // Functions iterating traversal.
3363 // These functions chain results into a single
3364 // selector.
3365 //////////////////////////////////////////
3366 forEach({
3367   removeData: jqLiteRemoveData,
3368
3369   on: function jqLiteOn(element, type, fn, unsupported) {
3370     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3371
3372     // Do not add event handlers to non-elements because they will not be cleaned up.
3373     if (!jqLiteAcceptsData(element)) {
3374       return;
3375     }
3376
3377     var expandoStore = jqLiteExpandoStore(element, true);
3378     var events = expandoStore.events;
3379     var handle = expandoStore.handle;
3380
3381     if (!handle) {
3382       handle = expandoStore.handle = createEventHandler(element, events);
3383     }
3384
3385     // http://jsperf.com/string-indexof-vs-split
3386     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3387     var i = types.length;
3388
3389     var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3390       var eventFns = events[type];
3391
3392       if (!eventFns) {
3393         eventFns = events[type] = [];
3394         eventFns.specialHandlerWrapper = specialHandlerWrapper;
3395         if (type !== '$destroy' && !noEventListener) {
3396           addEventListenerFn(element, type, handle);
3397         }
3398       }
3399
3400       eventFns.push(fn);
3401     };
3402
3403     while (i--) {
3404       type = types[i];
3405       if (MOUSE_EVENT_MAP[type]) {
3406         addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3407         addHandler(type, undefined, true);
3408       } else {
3409         addHandler(type);
3410       }
3411     }
3412   },
3413
3414   off: jqLiteOff,
3415
3416   one: function(element, type, fn) {
3417     element = jqLite(element);
3418
3419     //add the listener twice so that when it is called
3420     //you can remove the original function and still be
3421     //able to call element.off(ev, fn) normally
3422     element.on(type, function onFn() {
3423       element.off(type, fn);
3424       element.off(type, onFn);
3425     });
3426     element.on(type, fn);
3427   },
3428
3429   replaceWith: function(element, replaceNode) {
3430     var index, parent = element.parentNode;
3431     jqLiteDealoc(element);
3432     forEach(new JQLite(replaceNode), function(node) {
3433       if (index) {
3434         parent.insertBefore(node, index.nextSibling);
3435       } else {
3436         parent.replaceChild(node, element);
3437       }
3438       index = node;
3439     });
3440   },
3441
3442   children: function(element) {
3443     var children = [];
3444     forEach(element.childNodes, function(element) {
3445       if (element.nodeType === NODE_TYPE_ELEMENT) {
3446         children.push(element);
3447       }
3448     });
3449     return children;
3450   },
3451
3452   contents: function(element) {
3453     return element.contentDocument || element.childNodes || [];
3454   },
3455
3456   append: function(element, node) {
3457     var nodeType = element.nodeType;
3458     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3459
3460     node = new JQLite(node);
3461
3462     for (var i = 0, ii = node.length; i < ii; i++) {
3463       var child = node[i];
3464       element.appendChild(child);
3465     }
3466   },
3467
3468   prepend: function(element, node) {
3469     if (element.nodeType === NODE_TYPE_ELEMENT) {
3470       var index = element.firstChild;
3471       forEach(new JQLite(node), function(child) {
3472         element.insertBefore(child, index);
3473       });
3474     }
3475   },
3476
3477   wrap: function(element, wrapNode) {
3478     wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3479     var parent = element.parentNode;
3480     if (parent) {
3481       parent.replaceChild(wrapNode, element);
3482     }
3483     wrapNode.appendChild(element);
3484   },
3485
3486   remove: jqLiteRemove,
3487
3488   detach: function(element) {
3489     jqLiteRemove(element, true);
3490   },
3491
3492   after: function(element, newElement) {
3493     var index = element, parent = element.parentNode;
3494     newElement = new JQLite(newElement);
3495
3496     for (var i = 0, ii = newElement.length; i < ii; i++) {
3497       var node = newElement[i];
3498       parent.insertBefore(node, index.nextSibling);
3499       index = node;
3500     }
3501   },
3502
3503   addClass: jqLiteAddClass,
3504   removeClass: jqLiteRemoveClass,
3505
3506   toggleClass: function(element, selector, condition) {
3507     if (selector) {
3508       forEach(selector.split(' '), function(className) {
3509         var classCondition = condition;
3510         if (isUndefined(classCondition)) {
3511           classCondition = !jqLiteHasClass(element, className);
3512         }
3513         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3514       });
3515     }
3516   },
3517
3518   parent: function(element) {
3519     var parent = element.parentNode;
3520     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3521   },
3522
3523   next: function(element) {
3524     return element.nextElementSibling;
3525   },
3526
3527   find: function(element, selector) {
3528     if (element.getElementsByTagName) {
3529       return element.getElementsByTagName(selector);
3530     } else {
3531       return [];
3532     }
3533   },
3534
3535   clone: jqLiteClone,
3536
3537   triggerHandler: function(element, event, extraParameters) {
3538
3539     var dummyEvent, eventFnsCopy, handlerArgs;
3540     var eventName = event.type || event;
3541     var expandoStore = jqLiteExpandoStore(element);
3542     var events = expandoStore && expandoStore.events;
3543     var eventFns = events && events[eventName];
3544
3545     if (eventFns) {
3546       // Create a dummy event to pass to the handlers
3547       dummyEvent = {
3548         preventDefault: function() { this.defaultPrevented = true; },
3549         isDefaultPrevented: function() { return this.defaultPrevented === true; },
3550         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3551         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3552         stopPropagation: noop,
3553         type: eventName,
3554         target: element
3555       };
3556
3557       // If a custom event was provided then extend our dummy event with it
3558       if (event.type) {
3559         dummyEvent = extend(dummyEvent, event);
3560       }
3561
3562       // Copy event handlers in case event handlers array is modified during execution.
3563       eventFnsCopy = shallowCopy(eventFns);
3564       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3565
3566       forEach(eventFnsCopy, function(fn) {
3567         if (!dummyEvent.isImmediatePropagationStopped()) {
3568           fn.apply(element, handlerArgs);
3569         }
3570       });
3571     }
3572   }
3573 }, function(fn, name) {
3574   /**
3575    * chaining functions
3576    */
3577   JQLite.prototype[name] = function(arg1, arg2, arg3) {
3578     var value;
3579
3580     for (var i = 0, ii = this.length; i < ii; i++) {
3581       if (isUndefined(value)) {
3582         value = fn(this[i], arg1, arg2, arg3);
3583         if (isDefined(value)) {
3584           // any function which returns a value needs to be wrapped
3585           value = jqLite(value);
3586         }
3587       } else {
3588         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3589       }
3590     }
3591     return isDefined(value) ? value : this;
3592   };
3593
3594   // bind legacy bind/unbind to on/off
3595   JQLite.prototype.bind = JQLite.prototype.on;
3596   JQLite.prototype.unbind = JQLite.prototype.off;
3597 });
3598
3599
3600 // Provider for private $$jqLite service
3601 function $$jqLiteProvider() {
3602   this.$get = function $$jqLite() {
3603     return extend(JQLite, {
3604       hasClass: function(node, classes) {
3605         if (node.attr) node = node[0];
3606         return jqLiteHasClass(node, classes);
3607       },
3608       addClass: function(node, classes) {
3609         if (node.attr) node = node[0];
3610         return jqLiteAddClass(node, classes);
3611       },
3612       removeClass: function(node, classes) {
3613         if (node.attr) node = node[0];
3614         return jqLiteRemoveClass(node, classes);
3615       }
3616     });
3617   };
3618 }
3619
3620 /**
3621  * Computes a hash of an 'obj'.
3622  * Hash of a:
3623  *  string is string
3624  *  number is number as string
3625  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3626  *         that is also assigned to the $$hashKey property of the object.
3627  *
3628  * @param obj
3629  * @returns {string} hash string such that the same input will have the same hash string.
3630  *         The resulting string key is in 'type:hashKey' format.
3631  */
3632 function hashKey(obj, nextUidFn) {
3633   var key = obj && obj.$$hashKey;
3634
3635   if (key) {
3636     if (typeof key === 'function') {
3637       key = obj.$$hashKey();
3638     }
3639     return key;
3640   }
3641
3642   var objType = typeof obj;
3643   if (objType == 'function' || (objType == 'object' && obj !== null)) {
3644     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3645   } else {
3646     key = objType + ':' + obj;
3647   }
3648
3649   return key;
3650 }
3651
3652 /**
3653  * HashMap which can use objects as keys
3654  */
3655 function HashMap(array, isolatedUid) {
3656   if (isolatedUid) {
3657     var uid = 0;
3658     this.nextUid = function() {
3659       return ++uid;
3660     };
3661   }
3662   forEach(array, this.put, this);
3663 }
3664 HashMap.prototype = {
3665   /**
3666    * Store key value pair
3667    * @param key key to store can be any type
3668    * @param value value to store can be any type
3669    */
3670   put: function(key, value) {
3671     this[hashKey(key, this.nextUid)] = value;
3672   },
3673
3674   /**
3675    * @param key
3676    * @returns {Object} the value for the key
3677    */
3678   get: function(key) {
3679     return this[hashKey(key, this.nextUid)];
3680   },
3681
3682   /**
3683    * Remove the key/value pair
3684    * @param key
3685    */
3686   remove: function(key) {
3687     var value = this[key = hashKey(key, this.nextUid)];
3688     delete this[key];
3689     return value;
3690   }
3691 };
3692
3693 var $$HashMapProvider = [function() {
3694   this.$get = [function() {
3695     return HashMap;
3696   }];
3697 }];
3698
3699 /**
3700  * @ngdoc function
3701  * @module ng
3702  * @name angular.injector
3703  * @kind function
3704  *
3705  * @description
3706  * Creates an injector object that can be used for retrieving services as well as for
3707  * dependency injection (see {@link guide/di dependency injection}).
3708  *
3709  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3710  *     {@link angular.module}. The `ng` module must be explicitly added.
3711  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3712  *     disallows argument name annotation inference.
3713  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3714  *
3715  * @example
3716  * Typical usage
3717  * ```js
3718  *   // create an injector
3719  *   var $injector = angular.injector(['ng']);
3720  *
3721  *   // use the injector to kick off your application
3722  *   // use the type inference to auto inject arguments, or use implicit injection
3723  *   $injector.invoke(function($rootScope, $compile, $document) {
3724  *     $compile($document)($rootScope);
3725  *     $rootScope.$digest();
3726  *   });
3727  * ```
3728  *
3729  * Sometimes you want to get access to the injector of a currently running Angular app
3730  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3731  * application has been bootstrapped. You can do this using the extra `injector()` added
3732  * to JQuery/jqLite elements. See {@link angular.element}.
3733  *
3734  * *This is fairly rare but could be the case if a third party library is injecting the
3735  * markup.*
3736  *
3737  * In the following example a new block of HTML containing a `ng-controller`
3738  * directive is added to the end of the document body by JQuery. We then compile and link
3739  * it into the current AngularJS scope.
3740  *
3741  * ```js
3742  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3743  * $(document.body).append($div);
3744  *
3745  * angular.element(document).injector().invoke(function($compile) {
3746  *   var scope = angular.element($div).scope();
3747  *   $compile($div)(scope);
3748  * });
3749  * ```
3750  */
3751
3752
3753 /**
3754  * @ngdoc module
3755  * @name auto
3756  * @description
3757  *
3758  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3759  */
3760
3761 var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3762 var FN_ARG_SPLIT = /,/;
3763 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3764 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3765 var $injectorMinErr = minErr('$injector');
3766
3767 function anonFn(fn) {
3768   // For anonymous functions, showing at the very least the function signature can help in
3769   // debugging.
3770   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3771       args = fnText.match(FN_ARGS);
3772   if (args) {
3773     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3774   }
3775   return 'fn';
3776 }
3777
3778 function annotate(fn, strictDi, name) {
3779   var $inject,
3780       fnText,
3781       argDecl,
3782       last;
3783
3784   if (typeof fn === 'function') {
3785     if (!($inject = fn.$inject)) {
3786       $inject = [];
3787       if (fn.length) {
3788         if (strictDi) {
3789           if (!isString(name) || !name) {
3790             name = fn.name || anonFn(fn);
3791           }
3792           throw $injectorMinErr('strictdi',
3793             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3794         }
3795         fnText = fn.toString().replace(STRIP_COMMENTS, '');
3796         argDecl = fnText.match(FN_ARGS);
3797         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3798           arg.replace(FN_ARG, function(all, underscore, name) {
3799             $inject.push(name);
3800           });
3801         });
3802       }
3803       fn.$inject = $inject;
3804     }
3805   } else if (isArray(fn)) {
3806     last = fn.length - 1;
3807     assertArgFn(fn[last], 'fn');
3808     $inject = fn.slice(0, last);
3809   } else {
3810     assertArgFn(fn, 'fn', true);
3811   }
3812   return $inject;
3813 }
3814
3815 ///////////////////////////////////////
3816
3817 /**
3818  * @ngdoc service
3819  * @name $injector
3820  *
3821  * @description
3822  *
3823  * `$injector` is used to retrieve object instances as defined by
3824  * {@link auto.$provide provider}, instantiate types, invoke methods,
3825  * and load modules.
3826  *
3827  * The following always holds true:
3828  *
3829  * ```js
3830  *   var $injector = angular.injector();
3831  *   expect($injector.get('$injector')).toBe($injector);
3832  *   expect($injector.invoke(function($injector) {
3833  *     return $injector;
3834  *   })).toBe($injector);
3835  * ```
3836  *
3837  * # Injection Function Annotation
3838  *
3839  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3840  * following are all valid ways of annotating function with injection arguments and are equivalent.
3841  *
3842  * ```js
3843  *   // inferred (only works if code not minified/obfuscated)
3844  *   $injector.invoke(function(serviceA){});
3845  *
3846  *   // annotated
3847  *   function explicit(serviceA) {};
3848  *   explicit.$inject = ['serviceA'];
3849  *   $injector.invoke(explicit);
3850  *
3851  *   // inline
3852  *   $injector.invoke(['serviceA', function(serviceA){}]);
3853  * ```
3854  *
3855  * ## Inference
3856  *
3857  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3858  * can then be parsed and the function arguments can be extracted. This method of discovering
3859  * annotations is disallowed when the injector is in strict mode.
3860  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3861  * argument names.
3862  *
3863  * ## `$inject` Annotation
3864  * By adding an `$inject` property onto a function the injection parameters can be specified.
3865  *
3866  * ## Inline
3867  * As an array of injection names, where the last item in the array is the function to call.
3868  */
3869
3870 /**
3871  * @ngdoc method
3872  * @name $injector#get
3873  *
3874  * @description
3875  * Return an instance of the service.
3876  *
3877  * @param {string} name The name of the instance to retrieve.
3878  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3879  * @return {*} The instance.
3880  */
3881
3882 /**
3883  * @ngdoc method
3884  * @name $injector#invoke
3885  *
3886  * @description
3887  * Invoke the method and supply the method arguments from the `$injector`.
3888  *
3889  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3890  *   injected according to the {@link guide/di $inject Annotation} rules.
3891  * @param {Object=} self The `this` for the invoked method.
3892  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3893  *                         object first, before the `$injector` is consulted.
3894  * @returns {*} the value returned by the invoked `fn` function.
3895  */
3896
3897 /**
3898  * @ngdoc method
3899  * @name $injector#has
3900  *
3901  * @description
3902  * Allows the user to query if the particular service exists.
3903  *
3904  * @param {string} name Name of the service to query.
3905  * @returns {boolean} `true` if injector has given service.
3906  */
3907
3908 /**
3909  * @ngdoc method
3910  * @name $injector#instantiate
3911  * @description
3912  * Create a new instance of JS type. The method takes a constructor function, invokes the new
3913  * operator, and supplies all of the arguments to the constructor function as specified by the
3914  * constructor annotation.
3915  *
3916  * @param {Function} Type Annotated constructor function.
3917  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3918  * object first, before the `$injector` is consulted.
3919  * @returns {Object} new instance of `Type`.
3920  */
3921
3922 /**
3923  * @ngdoc method
3924  * @name $injector#annotate
3925  *
3926  * @description
3927  * Returns an array of service names which the function is requesting for injection. This API is
3928  * used by the injector to determine which services need to be injected into the function when the
3929  * function is invoked. There are three ways in which the function can be annotated with the needed
3930  * dependencies.
3931  *
3932  * # Argument names
3933  *
3934  * The simplest form is to extract the dependencies from the arguments of the function. This is done
3935  * by converting the function into a string using `toString()` method and extracting the argument
3936  * names.
3937  * ```js
3938  *   // Given
3939  *   function MyController($scope, $route) {
3940  *     // ...
3941  *   }
3942  *
3943  *   // Then
3944  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3945  * ```
3946  *
3947  * You can disallow this method by using strict injection mode.
3948  *
3949  * This method does not work with code minification / obfuscation. For this reason the following
3950  * annotation strategies are supported.
3951  *
3952  * # The `$inject` property
3953  *
3954  * If a function has an `$inject` property and its value is an array of strings, then the strings
3955  * represent names of services to be injected into the function.
3956  * ```js
3957  *   // Given
3958  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3959  *     // ...
3960  *   }
3961  *   // Define function dependencies
3962  *   MyController['$inject'] = ['$scope', '$route'];
3963  *
3964  *   // Then
3965  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3966  * ```
3967  *
3968  * # The array notation
3969  *
3970  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3971  * is very inconvenient. In these situations using the array notation to specify the dependencies in
3972  * a way that survives minification is a better choice:
3973  *
3974  * ```js
3975  *   // We wish to write this (not minification / obfuscation safe)
3976  *   injector.invoke(function($compile, $rootScope) {
3977  *     // ...
3978  *   });
3979  *
3980  *   // We are forced to write break inlining
3981  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3982  *     // ...
3983  *   };
3984  *   tmpFn.$inject = ['$compile', '$rootScope'];
3985  *   injector.invoke(tmpFn);
3986  *
3987  *   // To better support inline function the inline annotation is supported
3988  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3989  *     // ...
3990  *   }]);
3991  *
3992  *   // Therefore
3993  *   expect(injector.annotate(
3994  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3995  *    ).toEqual(['$compile', '$rootScope']);
3996  * ```
3997  *
3998  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3999  * be retrieved as described above.
4000  *
4001  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4002  *
4003  * @returns {Array.<string>} The names of the services which the function requires.
4004  */
4005
4006
4007
4008
4009 /**
4010  * @ngdoc service
4011  * @name $provide
4012  *
4013  * @description
4014  *
4015  * The {@link auto.$provide $provide} service has a number of methods for registering components
4016  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4017  * {@link angular.Module}.
4018  *
4019  * An Angular **service** is a singleton object created by a **service factory**.  These **service
4020  * factories** are functions which, in turn, are created by a **service provider**.
4021  * The **service providers** are constructor functions. When instantiated they must contain a
4022  * property called `$get`, which holds the **service factory** function.
4023  *
4024  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4025  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4026  * function to get the instance of the **service**.
4027  *
4028  * Often services have no configuration options and there is no need to add methods to the service
4029  * provider.  The provider will be no more than a constructor function with a `$get` property. For
4030  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4031  * services without specifying a provider.
4032  *
4033  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
4034  *     {@link auto.$injector $injector}
4035  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
4036  *     providers and services.
4037  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
4038  *     services, not providers.
4039  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
4040  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4041  *     given factory function.
4042  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
4043  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4044  *      a new object using the given constructor function.
4045  *
4046  * See the individual methods for more information and examples.
4047  */
4048
4049 /**
4050  * @ngdoc method
4051  * @name $provide#provider
4052  * @description
4053  *
4054  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4055  * are constructor functions, whose instances are responsible for "providing" a factory for a
4056  * service.
4057  *
4058  * Service provider names start with the name of the service they provide followed by `Provider`.
4059  * For example, the {@link ng.$log $log} service has a provider called
4060  * {@link ng.$logProvider $logProvider}.
4061  *
4062  * Service provider objects can have additional methods which allow configuration of the provider
4063  * and its service. Importantly, you can configure what kind of service is created by the `$get`
4064  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4065  * method {@link ng.$logProvider#debugEnabled debugEnabled}
4066  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4067  * console or not.
4068  *
4069  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4070                         'Provider'` key.
4071  * @param {(Object|function())} provider If the provider is:
4072  *
4073  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4074  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4075  *   - `Constructor`: a new instance of the provider will be created using
4076  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4077  *
4078  * @returns {Object} registered provider instance
4079
4080  * @example
4081  *
4082  * The following example shows how to create a simple event tracking service and register it using
4083  * {@link auto.$provide#provider $provide.provider()}.
4084  *
4085  * ```js
4086  *  // Define the eventTracker provider
4087  *  function EventTrackerProvider() {
4088  *    var trackingUrl = '/track';
4089  *
4090  *    // A provider method for configuring where the tracked events should been saved
4091  *    this.setTrackingUrl = function(url) {
4092  *      trackingUrl = url;
4093  *    };
4094  *
4095  *    // The service factory function
4096  *    this.$get = ['$http', function($http) {
4097  *      var trackedEvents = {};
4098  *      return {
4099  *        // Call this to track an event
4100  *        event: function(event) {
4101  *          var count = trackedEvents[event] || 0;
4102  *          count += 1;
4103  *          trackedEvents[event] = count;
4104  *          return count;
4105  *        },
4106  *        // Call this to save the tracked events to the trackingUrl
4107  *        save: function() {
4108  *          $http.post(trackingUrl, trackedEvents);
4109  *        }
4110  *      };
4111  *    }];
4112  *  }
4113  *
4114  *  describe('eventTracker', function() {
4115  *    var postSpy;
4116  *
4117  *    beforeEach(module(function($provide) {
4118  *      // Register the eventTracker provider
4119  *      $provide.provider('eventTracker', EventTrackerProvider);
4120  *    }));
4121  *
4122  *    beforeEach(module(function(eventTrackerProvider) {
4123  *      // Configure eventTracker provider
4124  *      eventTrackerProvider.setTrackingUrl('/custom-track');
4125  *    }));
4126  *
4127  *    it('tracks events', inject(function(eventTracker) {
4128  *      expect(eventTracker.event('login')).toEqual(1);
4129  *      expect(eventTracker.event('login')).toEqual(2);
4130  *    }));
4131  *
4132  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4133  *      postSpy = spyOn($http, 'post');
4134  *      eventTracker.event('login');
4135  *      eventTracker.save();
4136  *      expect(postSpy).toHaveBeenCalled();
4137  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4138  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4139  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4140  *    }));
4141  *  });
4142  * ```
4143  */
4144
4145 /**
4146  * @ngdoc method
4147  * @name $provide#factory
4148  * @description
4149  *
4150  * Register a **service factory**, which will be called to return the service instance.
4151  * This is short for registering a service where its provider consists of only a `$get` property,
4152  * which is the given service factory function.
4153  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4154  * configure your service in a provider.
4155  *
4156  * @param {string} name The name of the instance.
4157  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4158  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4159  * @returns {Object} registered provider instance
4160  *
4161  * @example
4162  * Here is an example of registering a service
4163  * ```js
4164  *   $provide.factory('ping', ['$http', function($http) {
4165  *     return function ping() {
4166  *       return $http.send('/ping');
4167  *     };
4168  *   }]);
4169  * ```
4170  * You would then inject and use this service like this:
4171  * ```js
4172  *   someModule.controller('Ctrl', ['ping', function(ping) {
4173  *     ping();
4174  *   }]);
4175  * ```
4176  */
4177
4178
4179 /**
4180  * @ngdoc method
4181  * @name $provide#service
4182  * @description
4183  *
4184  * Register a **service constructor**, which will be invoked with `new` to create the service
4185  * instance.
4186  * This is short for registering a service where its provider's `$get` property is the service
4187  * constructor function that will be used to instantiate the service instance.
4188  *
4189  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4190  * as a type/class.
4191  *
4192  * @param {string} name The name of the instance.
4193  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4194  *     that will be instantiated.
4195  * @returns {Object} registered provider instance
4196  *
4197  * @example
4198  * Here is an example of registering a service using
4199  * {@link auto.$provide#service $provide.service(class)}.
4200  * ```js
4201  *   var Ping = function($http) {
4202  *     this.$http = $http;
4203  *   };
4204  *
4205  *   Ping.$inject = ['$http'];
4206  *
4207  *   Ping.prototype.send = function() {
4208  *     return this.$http.get('/ping');
4209  *   };
4210  *   $provide.service('ping', Ping);
4211  * ```
4212  * You would then inject and use this service like this:
4213  * ```js
4214  *   someModule.controller('Ctrl', ['ping', function(ping) {
4215  *     ping.send();
4216  *   }]);
4217  * ```
4218  */
4219
4220
4221 /**
4222  * @ngdoc method
4223  * @name $provide#value
4224  * @description
4225  *
4226  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4227  * number, an array, an object or a function.  This is short for registering a service where its
4228  * provider's `$get` property is a factory function that takes no arguments and returns the **value
4229  * service**.
4230  *
4231  * Value services are similar to constant services, except that they cannot be injected into a
4232  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4233  * an Angular
4234  * {@link auto.$provide#decorator decorator}.
4235  *
4236  * @param {string} name The name of the instance.
4237  * @param {*} value The value.
4238  * @returns {Object} registered provider instance
4239  *
4240  * @example
4241  * Here are some examples of creating value services.
4242  * ```js
4243  *   $provide.value('ADMIN_USER', 'admin');
4244  *
4245  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4246  *
4247  *   $provide.value('halfOf', function(value) {
4248  *     return value / 2;
4249  *   });
4250  * ```
4251  */
4252
4253
4254 /**
4255  * @ngdoc method
4256  * @name $provide#constant
4257  * @description
4258  *
4259  * Register a **constant service**, such as a string, a number, an array, an object or a function,
4260  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4261  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4262  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4263  *
4264  * @param {string} name The name of the constant.
4265  * @param {*} value The constant value.
4266  * @returns {Object} registered instance
4267  *
4268  * @example
4269  * Here a some examples of creating constants:
4270  * ```js
4271  *   $provide.constant('SHARD_HEIGHT', 306);
4272  *
4273  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4274  *
4275  *   $provide.constant('double', function(value) {
4276  *     return value * 2;
4277  *   });
4278  * ```
4279  */
4280
4281
4282 /**
4283  * @ngdoc method
4284  * @name $provide#decorator
4285  * @description
4286  *
4287  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4288  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4289  * service. The object returned by the decorator may be the original service, or a new service
4290  * object which replaces or wraps and delegates to the original service.
4291  *
4292  * @param {string} name The name of the service to decorate.
4293  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4294  *    instantiated and should return the decorated service instance. The function is called using
4295  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4296  *    Local injection arguments:
4297  *
4298  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
4299  *      decorated or delegated to.
4300  *
4301  * @example
4302  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4303  * calls to {@link ng.$log#error $log.warn()}.
4304  * ```js
4305  *   $provide.decorator('$log', ['$delegate', function($delegate) {
4306  *     $delegate.warn = $delegate.error;
4307  *     return $delegate;
4308  *   }]);
4309  * ```
4310  */
4311
4312
4313 function createInjector(modulesToLoad, strictDi) {
4314   strictDi = (strictDi === true);
4315   var INSTANTIATING = {},
4316       providerSuffix = 'Provider',
4317       path = [],
4318       loadedModules = new HashMap([], true),
4319       providerCache = {
4320         $provide: {
4321             provider: supportObject(provider),
4322             factory: supportObject(factory),
4323             service: supportObject(service),
4324             value: supportObject(value),
4325             constant: supportObject(constant),
4326             decorator: decorator
4327           }
4328       },
4329       providerInjector = (providerCache.$injector =
4330           createInternalInjector(providerCache, function(serviceName, caller) {
4331             if (angular.isString(caller)) {
4332               path.push(caller);
4333             }
4334             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4335           })),
4336       instanceCache = {},
4337       instanceInjector = (instanceCache.$injector =
4338           createInternalInjector(instanceCache, function(serviceName, caller) {
4339             var provider = providerInjector.get(serviceName + providerSuffix, caller);
4340             return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4341           }));
4342
4343
4344   forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
4345
4346   return instanceInjector;
4347
4348   ////////////////////////////////////
4349   // $provider
4350   ////////////////////////////////////
4351
4352   function supportObject(delegate) {
4353     return function(key, value) {
4354       if (isObject(key)) {
4355         forEach(key, reverseParams(delegate));
4356       } else {
4357         return delegate(key, value);
4358       }
4359     };
4360   }
4361
4362   function provider(name, provider_) {
4363     assertNotHasOwnProperty(name, 'service');
4364     if (isFunction(provider_) || isArray(provider_)) {
4365       provider_ = providerInjector.instantiate(provider_);
4366     }
4367     if (!provider_.$get) {
4368       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4369     }
4370     return providerCache[name + providerSuffix] = provider_;
4371   }
4372
4373   function enforceReturnValue(name, factory) {
4374     return function enforcedReturnValue() {
4375       var result = instanceInjector.invoke(factory, this);
4376       if (isUndefined(result)) {
4377         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4378       }
4379       return result;
4380     };
4381   }
4382
4383   function factory(name, factoryFn, enforce) {
4384     return provider(name, {
4385       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4386     });
4387   }
4388
4389   function service(name, constructor) {
4390     return factory(name, ['$injector', function($injector) {
4391       return $injector.instantiate(constructor);
4392     }]);
4393   }
4394
4395   function value(name, val) { return factory(name, valueFn(val), false); }
4396
4397   function constant(name, value) {
4398     assertNotHasOwnProperty(name, 'constant');
4399     providerCache[name] = value;
4400     instanceCache[name] = value;
4401   }
4402
4403   function decorator(serviceName, decorFn) {
4404     var origProvider = providerInjector.get(serviceName + providerSuffix),
4405         orig$get = origProvider.$get;
4406
4407     origProvider.$get = function() {
4408       var origInstance = instanceInjector.invoke(orig$get, origProvider);
4409       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4410     };
4411   }
4412
4413   ////////////////////////////////////
4414   // Module Loading
4415   ////////////////////////////////////
4416   function loadModules(modulesToLoad) {
4417     assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4418     var runBlocks = [], moduleFn;
4419     forEach(modulesToLoad, function(module) {
4420       if (loadedModules.get(module)) return;
4421       loadedModules.put(module, true);
4422
4423       function runInvokeQueue(queue) {
4424         var i, ii;
4425         for (i = 0, ii = queue.length; i < ii; i++) {
4426           var invokeArgs = queue[i],
4427               provider = providerInjector.get(invokeArgs[0]);
4428
4429           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4430         }
4431       }
4432
4433       try {
4434         if (isString(module)) {
4435           moduleFn = angularModule(module);
4436           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4437           runInvokeQueue(moduleFn._invokeQueue);
4438           runInvokeQueue(moduleFn._configBlocks);
4439         } else if (isFunction(module)) {
4440             runBlocks.push(providerInjector.invoke(module));
4441         } else if (isArray(module)) {
4442             runBlocks.push(providerInjector.invoke(module));
4443         } else {
4444           assertArgFn(module, 'module');
4445         }
4446       } catch (e) {
4447         if (isArray(module)) {
4448           module = module[module.length - 1];
4449         }
4450         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4451           // Safari & FF's stack traces don't contain error.message content
4452           // unlike those of Chrome and IE
4453           // So if stack doesn't contain message, we create a new string that contains both.
4454           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4455           /* jshint -W022 */
4456           e = e.message + '\n' + e.stack;
4457         }
4458         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4459                   module, e.stack || e.message || e);
4460       }
4461     });
4462     return runBlocks;
4463   }
4464
4465   ////////////////////////////////////
4466   // internal Injector
4467   ////////////////////////////////////
4468
4469   function createInternalInjector(cache, factory) {
4470
4471     function getService(serviceName, caller) {
4472       if (cache.hasOwnProperty(serviceName)) {
4473         if (cache[serviceName] === INSTANTIATING) {
4474           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4475                     serviceName + ' <- ' + path.join(' <- '));
4476         }
4477         return cache[serviceName];
4478       } else {
4479         try {
4480           path.unshift(serviceName);
4481           cache[serviceName] = INSTANTIATING;
4482           return cache[serviceName] = factory(serviceName, caller);
4483         } catch (err) {
4484           if (cache[serviceName] === INSTANTIATING) {
4485             delete cache[serviceName];
4486           }
4487           throw err;
4488         } finally {
4489           path.shift();
4490         }
4491       }
4492     }
4493
4494     function invoke(fn, self, locals, serviceName) {
4495       if (typeof locals === 'string') {
4496         serviceName = locals;
4497         locals = null;
4498       }
4499
4500       var args = [],
4501           $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4502           length, i,
4503           key;
4504
4505       for (i = 0, length = $inject.length; i < length; i++) {
4506         key = $inject[i];
4507         if (typeof key !== 'string') {
4508           throw $injectorMinErr('itkn',
4509                   'Incorrect injection token! Expected service name as string, got {0}', key);
4510         }
4511         args.push(
4512           locals && locals.hasOwnProperty(key)
4513           ? locals[key]
4514           : getService(key, serviceName)
4515         );
4516       }
4517       if (isArray(fn)) {
4518         fn = fn[length];
4519       }
4520
4521       // http://jsperf.com/angularjs-invoke-apply-vs-switch
4522       // #5388
4523       return fn.apply(self, args);
4524     }
4525
4526     function instantiate(Type, locals, serviceName) {
4527       // Check if Type is annotated and use just the given function at n-1 as parameter
4528       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4529       // Object creation: http://jsperf.com/create-constructor/2
4530       var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4531       var returnedValue = invoke(Type, instance, locals, serviceName);
4532
4533       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4534     }
4535
4536     return {
4537       invoke: invoke,
4538       instantiate: instantiate,
4539       get: getService,
4540       annotate: createInjector.$$annotate,
4541       has: function(name) {
4542         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4543       }
4544     };
4545   }
4546 }
4547
4548 createInjector.$$annotate = annotate;
4549
4550 /**
4551  * @ngdoc provider
4552  * @name $anchorScrollProvider
4553  *
4554  * @description
4555  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4556  * {@link ng.$location#hash $location.hash()} changes.
4557  */
4558 function $AnchorScrollProvider() {
4559
4560   var autoScrollingEnabled = true;
4561
4562   /**
4563    * @ngdoc method
4564    * @name $anchorScrollProvider#disableAutoScrolling
4565    *
4566    * @description
4567    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4568    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4569    * Use this method to disable automatic scrolling.
4570    *
4571    * If automatic scrolling is disabled, one must explicitly call
4572    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4573    * current hash.
4574    */
4575   this.disableAutoScrolling = function() {
4576     autoScrollingEnabled = false;
4577   };
4578
4579   /**
4580    * @ngdoc service
4581    * @name $anchorScroll
4582    * @kind function
4583    * @requires $window
4584    * @requires $location
4585    * @requires $rootScope
4586    *
4587    * @description
4588    * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4589    * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4590    * in the
4591    * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
4592    *
4593    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4594    * match any anchor whenever it changes. This can be disabled by calling
4595    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4596    *
4597    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4598    * vertical scroll-offset (either fixed or dynamic).
4599    *
4600    * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4601    *                       {@link ng.$location#hash $location.hash()} will be used.
4602    *
4603    * @property {(number|function|jqLite)} yOffset
4604    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4605    * positioned elements at the top of the page, such as navbars, headers etc.
4606    *
4607    * `yOffset` can be specified in various ways:
4608    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4609    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4610    *   a number representing the offset (in pixels).<br /><br />
4611    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4612    *   the top of the page to the element's bottom will be used as offset.<br />
4613    *   **Note**: The element will be taken into account only as long as its `position` is set to
4614    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4615    *   their height and/or positioning according to the viewport's size.
4616    *
4617    * <br />
4618    * <div class="alert alert-warning">
4619    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4620    * not some child element.
4621    * </div>
4622    *
4623    * @example
4624      <example module="anchorScrollExample">
4625        <file name="index.html">
4626          <div id="scrollArea" ng-controller="ScrollController">
4627            <a ng-click="gotoBottom()">Go to bottom</a>
4628            <a id="bottom"></a> You're at the bottom!
4629          </div>
4630        </file>
4631        <file name="script.js">
4632          angular.module('anchorScrollExample', [])
4633            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4634              function ($scope, $location, $anchorScroll) {
4635                $scope.gotoBottom = function() {
4636                  // set the location.hash to the id of
4637                  // the element you wish to scroll to.
4638                  $location.hash('bottom');
4639
4640                  // call $anchorScroll()
4641                  $anchorScroll();
4642                };
4643              }]);
4644        </file>
4645        <file name="style.css">
4646          #scrollArea {
4647            height: 280px;
4648            overflow: auto;
4649          }
4650
4651          #bottom {
4652            display: block;
4653            margin-top: 2000px;
4654          }
4655        </file>
4656      </example>
4657    *
4658    * <hr />
4659    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4660    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4661    *
4662    * @example
4663      <example module="anchorScrollOffsetExample">
4664        <file name="index.html">
4665          <div class="fixed-header" ng-controller="headerCtrl">
4666            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4667              Go to anchor {{x}}
4668            </a>
4669          </div>
4670          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4671            Anchor {{x}} of 5
4672          </div>
4673        </file>
4674        <file name="script.js">
4675          angular.module('anchorScrollOffsetExample', [])
4676            .run(['$anchorScroll', function($anchorScroll) {
4677              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4678            }])
4679            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4680              function ($anchorScroll, $location, $scope) {
4681                $scope.gotoAnchor = function(x) {
4682                  var newHash = 'anchor' + x;
4683                  if ($location.hash() !== newHash) {
4684                    // set the $location.hash to `newHash` and
4685                    // $anchorScroll will automatically scroll to it
4686                    $location.hash('anchor' + x);
4687                  } else {
4688                    // call $anchorScroll() explicitly,
4689                    // since $location.hash hasn't changed
4690                    $anchorScroll();
4691                  }
4692                };
4693              }
4694            ]);
4695        </file>
4696        <file name="style.css">
4697          body {
4698            padding-top: 50px;
4699          }
4700
4701          .anchor {
4702            border: 2px dashed DarkOrchid;
4703            padding: 10px 10px 200px 10px;
4704          }
4705
4706          .fixed-header {
4707            background-color: rgba(0, 0, 0, 0.2);
4708            height: 50px;
4709            position: fixed;
4710            top: 0; left: 0; right: 0;
4711          }
4712
4713          .fixed-header > a {
4714            display: inline-block;
4715            margin: 5px 15px;
4716          }
4717        </file>
4718      </example>
4719    */
4720   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4721     var document = $window.document;
4722
4723     // Helper function to get first anchor from a NodeList
4724     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4725     //  and working in all supported browsers.)
4726     function getFirstAnchor(list) {
4727       var result = null;
4728       Array.prototype.some.call(list, function(element) {
4729         if (nodeName_(element) === 'a') {
4730           result = element;
4731           return true;
4732         }
4733       });
4734       return result;
4735     }
4736
4737     function getYOffset() {
4738
4739       var offset = scroll.yOffset;
4740
4741       if (isFunction(offset)) {
4742         offset = offset();
4743       } else if (isElement(offset)) {
4744         var elem = offset[0];
4745         var style = $window.getComputedStyle(elem);
4746         if (style.position !== 'fixed') {
4747           offset = 0;
4748         } else {
4749           offset = elem.getBoundingClientRect().bottom;
4750         }
4751       } else if (!isNumber(offset)) {
4752         offset = 0;
4753       }
4754
4755       return offset;
4756     }
4757
4758     function scrollTo(elem) {
4759       if (elem) {
4760         elem.scrollIntoView();
4761
4762         var offset = getYOffset();
4763
4764         if (offset) {
4765           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4766           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4767           // top of the viewport.
4768           //
4769           // IF the number of pixels from the top of `elem` to the end of the page's content is less
4770           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4771           // way down the page.
4772           //
4773           // This is often the case for elements near the bottom of the page.
4774           //
4775           // In such cases we do not need to scroll the whole `offset` up, just the difference between
4776           // the top of the element and the offset, which is enough to align the top of `elem` at the
4777           // desired position.
4778           var elemTop = elem.getBoundingClientRect().top;
4779           $window.scrollBy(0, elemTop - offset);
4780         }
4781       } else {
4782         $window.scrollTo(0, 0);
4783       }
4784     }
4785
4786     function scroll(hash) {
4787       hash = isString(hash) ? hash : $location.hash();
4788       var elm;
4789
4790       // empty hash, scroll to the top of the page
4791       if (!hash) scrollTo(null);
4792
4793       // element with given id
4794       else if ((elm = document.getElementById(hash))) scrollTo(elm);
4795
4796       // first anchor with given name :-D
4797       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4798
4799       // no element and hash == 'top', scroll to the top of the page
4800       else if (hash === 'top') scrollTo(null);
4801     }
4802
4803     // does not scroll when user clicks on anchor link that is currently on
4804     // (no url change, no $location.hash() change), browser native does scroll
4805     if (autoScrollingEnabled) {
4806       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4807         function autoScrollWatchAction(newVal, oldVal) {
4808           // skip the initial scroll if $location.hash is empty
4809           if (newVal === oldVal && newVal === '') return;
4810
4811           jqLiteDocumentLoaded(function() {
4812             $rootScope.$evalAsync(scroll);
4813           });
4814         });
4815     }
4816
4817     return scroll;
4818   }];
4819 }
4820
4821 var $animateMinErr = minErr('$animate');
4822 var ELEMENT_NODE = 1;
4823 var NG_ANIMATE_CLASSNAME = 'ng-animate';
4824
4825 function mergeClasses(a,b) {
4826   if (!a && !b) return '';
4827   if (!a) return b;
4828   if (!b) return a;
4829   if (isArray(a)) a = a.join(' ');
4830   if (isArray(b)) b = b.join(' ');
4831   return a + ' ' + b;
4832 }
4833
4834 function extractElementNode(element) {
4835   for (var i = 0; i < element.length; i++) {
4836     var elm = element[i];
4837     if (elm.nodeType === ELEMENT_NODE) {
4838       return elm;
4839     }
4840   }
4841 }
4842
4843 function splitClasses(classes) {
4844   if (isString(classes)) {
4845     classes = classes.split(' ');
4846   }
4847
4848   // Use createMap() to prevent class assumptions involving property names in
4849   // Object.prototype
4850   var obj = createMap();
4851   forEach(classes, function(klass) {
4852     // sometimes the split leaves empty string values
4853     // incase extra spaces were applied to the options
4854     if (klass.length) {
4855       obj[klass] = true;
4856     }
4857   });
4858   return obj;
4859 }
4860
4861 // if any other type of options value besides an Object value is
4862 // passed into the $animate.method() animation then this helper code
4863 // will be run which will ignore it. While this patch is not the
4864 // greatest solution to this, a lot of existing plugins depend on
4865 // $animate to either call the callback (< 1.2) or return a promise
4866 // that can be changed. This helper function ensures that the options
4867 // are wiped clean incase a callback function is provided.
4868 function prepareAnimateOptions(options) {
4869   return isObject(options)
4870       ? options
4871       : {};
4872 }
4873
4874 var $$CoreAnimateRunnerProvider = function() {
4875   this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4876     function AnimateRunner() {}
4877     AnimateRunner.all = noop;
4878     AnimateRunner.chain = noop;
4879     AnimateRunner.prototype = {
4880       end: noop,
4881       cancel: noop,
4882       resume: noop,
4883       pause: noop,
4884       complete: noop,
4885       then: function(pass, fail) {
4886         return $q(function(resolve) {
4887           $$rAF(function() {
4888             resolve();
4889           });
4890         }).then(pass, fail);
4891       }
4892     };
4893     return AnimateRunner;
4894   }];
4895 };
4896
4897 // this is prefixed with Core since it conflicts with
4898 // the animateQueueProvider defined in ngAnimate/animateQueue.js
4899 var $$CoreAnimateQueueProvider = function() {
4900   var postDigestQueue = new HashMap();
4901   var postDigestElements = [];
4902
4903   this.$get = ['$$AnimateRunner', '$rootScope',
4904        function($$AnimateRunner,   $rootScope) {
4905     return {
4906       enabled: noop,
4907       on: noop,
4908       off: noop,
4909       pin: noop,
4910
4911       push: function(element, event, options, domOperation) {
4912         domOperation        && domOperation();
4913
4914         options = options || {};
4915         options.from        && element.css(options.from);
4916         options.to          && element.css(options.to);
4917
4918         if (options.addClass || options.removeClass) {
4919           addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
4920         }
4921
4922         return new $$AnimateRunner(); // jshint ignore:line
4923       }
4924     };
4925
4926
4927     function updateData(data, classes, value) {
4928       var changed = false;
4929       if (classes) {
4930         classes = isString(classes) ? classes.split(' ') :
4931                   isArray(classes) ? classes : [];
4932         forEach(classes, function(className) {
4933           if (className) {
4934             changed = true;
4935             data[className] = value;
4936           }
4937         });
4938       }
4939       return changed;
4940     }
4941
4942     function handleCSSClassChanges() {
4943       forEach(postDigestElements, function(element) {
4944         var data = postDigestQueue.get(element);
4945         if (data) {
4946           var existing = splitClasses(element.attr('class'));
4947           var toAdd = '';
4948           var toRemove = '';
4949           forEach(data, function(status, className) {
4950             var hasClass = !!existing[className];
4951             if (status !== hasClass) {
4952               if (status) {
4953                 toAdd += (toAdd.length ? ' ' : '') + className;
4954               } else {
4955                 toRemove += (toRemove.length ? ' ' : '') + className;
4956               }
4957             }
4958           });
4959
4960           forEach(element, function(elm) {
4961             toAdd    && jqLiteAddClass(elm, toAdd);
4962             toRemove && jqLiteRemoveClass(elm, toRemove);
4963           });
4964           postDigestQueue.remove(element);
4965         }
4966       });
4967       postDigestElements.length = 0;
4968     }
4969
4970
4971     function addRemoveClassesPostDigest(element, add, remove) {
4972       var data = postDigestQueue.get(element) || {};
4973
4974       var classesAdded = updateData(data, add, true);
4975       var classesRemoved = updateData(data, remove, false);
4976
4977       if (classesAdded || classesRemoved) {
4978
4979         postDigestQueue.put(element, data);
4980         postDigestElements.push(element);
4981
4982         if (postDigestElements.length === 1) {
4983           $rootScope.$$postDigest(handleCSSClassChanges);
4984         }
4985       }
4986     }
4987   }];
4988 };
4989
4990 /**
4991  * @ngdoc provider
4992  * @name $animateProvider
4993  *
4994  * @description
4995  * Default implementation of $animate that doesn't perform any animations, instead just
4996  * synchronously performs DOM updates and resolves the returned runner promise.
4997  *
4998  * In order to enable animations the `ngAnimate` module has to be loaded.
4999  *
5000  * To see the functional implementation check out `src/ngAnimate/animate.js`.
5001  */
5002 var $AnimateProvider = ['$provide', function($provide) {
5003   var provider = this;
5004
5005   this.$$registeredAnimations = Object.create(null);
5006
5007    /**
5008    * @ngdoc method
5009    * @name $animateProvider#register
5010    *
5011    * @description
5012    * Registers a new injectable animation factory function. The factory function produces the
5013    * animation object which contains callback functions for each event that is expected to be
5014    * animated.
5015    *
5016    *   * `eventFn`: `function(element, ... , doneFunction, options)`
5017    *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5018    *   on the type of animation additional arguments will be injected into the animation function. The
5019    *   list below explains the function signatures for the different animation methods:
5020    *
5021    *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5022    *   - addClass: function(element, addedClasses, doneFunction, options)
5023    *   - removeClass: function(element, removedClasses, doneFunction, options)
5024    *   - enter, leave, move: function(element, doneFunction, options)
5025    *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5026    *
5027    *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5028    *
5029    * ```js
5030    *   return {
5031    *     //enter, leave, move signature
5032    *     eventFn : function(element, done, options) {
5033    *       //code to run the animation
5034    *       //once complete, then run done()
5035    *       return function endFunction(wasCancelled) {
5036    *         //code to cancel the animation
5037    *       }
5038    *     }
5039    *   }
5040    * ```
5041    *
5042    * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5043    * @param {Function} factory The factory function that will be executed to return the animation
5044    *                           object.
5045    */
5046   this.register = function(name, factory) {
5047     if (name && name.charAt(0) !== '.') {
5048       throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
5049     }
5050
5051     var key = name + '-animation';
5052     provider.$$registeredAnimations[name.substr(1)] = key;
5053     $provide.factory(key, factory);
5054   };
5055
5056   /**
5057    * @ngdoc method
5058    * @name $animateProvider#classNameFilter
5059    *
5060    * @description
5061    * Sets and/or returns the CSS class regular expression that is checked when performing
5062    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5063    * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5064    * When setting the `classNameFilter` value, animations will only be performed on elements
5065    * that successfully match the filter expression. This in turn can boost performance
5066    * for low-powered devices as well as applications containing a lot of structural operations.
5067    * @param {RegExp=} expression The className expression which will be checked against all animations
5068    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5069    */
5070   this.classNameFilter = function(expression) {
5071     if (arguments.length === 1) {
5072       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
5073       if (this.$$classNameFilter) {
5074         var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
5075         if (reservedRegex.test(this.$$classNameFilter.toString())) {
5076           throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5077
5078         }
5079       }
5080     }
5081     return this.$$classNameFilter;
5082   };
5083
5084   this.$get = ['$$animateQueue', function($$animateQueue) {
5085     function domInsert(element, parentElement, afterElement) {
5086       // if for some reason the previous element was removed
5087       // from the dom sometime before this code runs then let's
5088       // just stick to using the parent element as the anchor
5089       if (afterElement) {
5090         var afterNode = extractElementNode(afterElement);
5091         if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5092           afterElement = null;
5093         }
5094       }
5095       afterElement ? afterElement.after(element) : parentElement.prepend(element);
5096     }
5097
5098     /**
5099      * @ngdoc service
5100      * @name $animate
5101      * @description The $animate service exposes a series of DOM utility methods that provide support
5102      * for animation hooks. The default behavior is the application of DOM operations, however,
5103      * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5104      * to ensure that animation runs with the triggered DOM operation.
5105      *
5106      * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5107      * included and only when it is active then the animation hooks that `$animate` triggers will be
5108      * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5109      * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5110      * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5111      *
5112      * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5113      *
5114      * To learn more about enabling animation support, click here to visit the
5115      * {@link ngAnimate ngAnimate module page}.
5116      */
5117     return {
5118       // we don't call it directly since non-existant arguments may
5119       // be interpreted as null within the sub enabled function
5120
5121       /**
5122        *
5123        * @ngdoc method
5124        * @name $animate#on
5125        * @kind function
5126        * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5127        *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5128        *    is fired with the following params:
5129        *
5130        * ```js
5131        * $animate.on('enter', container,
5132        *    function callback(element, phase) {
5133        *      // cool we detected an enter animation within the container
5134        *    }
5135        * );
5136        * ```
5137        *
5138        * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5139        * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5140        *     as well as among its children
5141        * @param {Function} callback the callback function that will be fired when the listener is triggered
5142        *
5143        * The arguments present in the callback function are:
5144        * * `element` - The captured DOM element that the animation was fired on.
5145        * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5146        */
5147       on: $$animateQueue.on,
5148
5149       /**
5150        *
5151        * @ngdoc method
5152        * @name $animate#off
5153        * @kind function
5154        * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5155        * can be used in three different ways depending on the arguments:
5156        *
5157        * ```js
5158        * // remove all the animation event listeners listening for `enter`
5159        * $animate.off('enter');
5160        *
5161        * // remove all the animation event listeners listening for `enter` on the given element and its children
5162        * $animate.off('enter', container);
5163        *
5164        * // remove the event listener function provided by `listenerFn` that is set
5165        * // to listen for `enter` on the given `element` as well as its children
5166        * $animate.off('enter', container, callback);
5167        * ```
5168        *
5169        * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5170        * @param {DOMElement=} container the container element the event listener was placed on
5171        * @param {Function=} callback the callback function that was registered as the listener
5172        */
5173       off: $$animateQueue.off,
5174
5175       /**
5176        * @ngdoc method
5177        * @name $animate#pin
5178        * @kind function
5179        * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5180        *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5181        *    element despite being outside the realm of the application or within another application. Say for example if the application
5182        *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5183        *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5184        *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5185        *
5186        *    Note that this feature is only active when the `ngAnimate` module is used.
5187        *
5188        * @param {DOMElement} element the external element that will be pinned
5189        * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5190        */
5191       pin: $$animateQueue.pin,
5192
5193       /**
5194        *
5195        * @ngdoc method
5196        * @name $animate#enabled
5197        * @kind function
5198        * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5199        * function can be called in four ways:
5200        *
5201        * ```js
5202        * // returns true or false
5203        * $animate.enabled();
5204        *
5205        * // changes the enabled state for all animations
5206        * $animate.enabled(false);
5207        * $animate.enabled(true);
5208        *
5209        * // returns true or false if animations are enabled for an element
5210        * $animate.enabled(element);
5211        *
5212        * // changes the enabled state for an element and its children
5213        * $animate.enabled(element, true);
5214        * $animate.enabled(element, false);
5215        * ```
5216        *
5217        * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5218        * @param {boolean=} enabled whether or not the animations will be enabled for the element
5219        *
5220        * @return {boolean} whether or not animations are enabled
5221        */
5222       enabled: $$animateQueue.enabled,
5223
5224       /**
5225        * @ngdoc method
5226        * @name $animate#cancel
5227        * @kind function
5228        * @description Cancels the provided animation.
5229        *
5230        * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5231        */
5232       cancel: function(runner) {
5233         runner.end && runner.end();
5234       },
5235
5236       /**
5237        *
5238        * @ngdoc method
5239        * @name $animate#enter
5240        * @kind function
5241        * @description Inserts the element into the DOM either after the `after` element (if provided) or
5242        *   as the first child within the `parent` element and then triggers an animation.
5243        *   A promise is returned that will be resolved during the next digest once the animation
5244        *   has completed.
5245        *
5246        * @param {DOMElement} element the element which will be inserted into the DOM
5247        * @param {DOMElement} parent the parent element which will append the element as
5248        *   a child (so long as the after element is not present)
5249        * @param {DOMElement=} after the sibling element after which the element will be appended
5250        * @param {object=} options an optional collection of options/styles that will be applied to the element
5251        *
5252        * @return {Promise} the animation callback promise
5253        */
5254       enter: function(element, parent, after, options) {
5255         parent = parent && jqLite(parent);
5256         after = after && jqLite(after);
5257         parent = parent || after.parent();
5258         domInsert(element, parent, after);
5259         return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5260       },
5261
5262       /**
5263        *
5264        * @ngdoc method
5265        * @name $animate#move
5266        * @kind function
5267        * @description Inserts (moves) the element into its new position in the DOM either after
5268        *   the `after` element (if provided) or as the first child within the `parent` element
5269        *   and then triggers an animation. A promise is returned that will be resolved
5270        *   during the next digest once the animation has completed.
5271        *
5272        * @param {DOMElement} element the element which will be moved into the new DOM position
5273        * @param {DOMElement} parent the parent element which will append the element as
5274        *   a child (so long as the after element is not present)
5275        * @param {DOMElement=} after the sibling element after which the element will be appended
5276        * @param {object=} options an optional collection of options/styles that will be applied to the element
5277        *
5278        * @return {Promise} the animation callback promise
5279        */
5280       move: function(element, parent, after, options) {
5281         parent = parent && jqLite(parent);
5282         after = after && jqLite(after);
5283         parent = parent || after.parent();
5284         domInsert(element, parent, after);
5285         return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5286       },
5287
5288       /**
5289        * @ngdoc method
5290        * @name $animate#leave
5291        * @kind function
5292        * @description Triggers an animation and then removes the element from the DOM.
5293        * When the function is called a promise is returned that will be resolved during the next
5294        * digest once the animation has completed.
5295        *
5296        * @param {DOMElement} element the element which will be removed from the DOM
5297        * @param {object=} options an optional collection of options/styles that will be applied to the element
5298        *
5299        * @return {Promise} the animation callback promise
5300        */
5301       leave: function(element, options) {
5302         return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5303           element.remove();
5304         });
5305       },
5306
5307       /**
5308        * @ngdoc method
5309        * @name $animate#addClass
5310        * @kind function
5311        *
5312        * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5313        *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5314        *   animation if element already contains the CSS class or if the class is removed at a later step.
5315        *   Note that class-based animations are treated differently compared to structural animations
5316        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5317        *   depending if CSS or JavaScript animations are used.
5318        *
5319        * @param {DOMElement} element the element which the CSS classes will be applied to
5320        * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5321        * @param {object=} options an optional collection of options/styles that will be applied to the element
5322        *
5323        * @return {Promise} the animation callback promise
5324        */
5325       addClass: function(element, className, options) {
5326         options = prepareAnimateOptions(options);
5327         options.addClass = mergeClasses(options.addclass, className);
5328         return $$animateQueue.push(element, 'addClass', options);
5329       },
5330
5331       /**
5332        * @ngdoc method
5333        * @name $animate#removeClass
5334        * @kind function
5335        *
5336        * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5337        *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5338        *   animation if element does not contain the CSS class or if the class is added at a later step.
5339        *   Note that class-based animations are treated differently compared to structural animations
5340        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5341        *   depending if CSS or JavaScript animations are used.
5342        *
5343        * @param {DOMElement} element the element which the CSS classes will be applied to
5344        * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5345        * @param {object=} options an optional collection of options/styles that will be applied to the element
5346        *
5347        * @return {Promise} the animation callback promise
5348        */
5349       removeClass: function(element, className, options) {
5350         options = prepareAnimateOptions(options);
5351         options.removeClass = mergeClasses(options.removeClass, className);
5352         return $$animateQueue.push(element, 'removeClass', options);
5353       },
5354
5355       /**
5356        * @ngdoc method
5357        * @name $animate#setClass
5358        * @kind function
5359        *
5360        * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5361        *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5362        *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5363        *    passed. Note that class-based animations are treated differently compared to structural animations
5364        *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5365        *    depending if CSS or JavaScript animations are used.
5366        *
5367        * @param {DOMElement} element the element which the CSS classes will be applied to
5368        * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5369        * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5370        * @param {object=} options an optional collection of options/styles that will be applied to the element
5371        *
5372        * @return {Promise} the animation callback promise
5373        */
5374       setClass: function(element, add, remove, options) {
5375         options = prepareAnimateOptions(options);
5376         options.addClass = mergeClasses(options.addClass, add);
5377         options.removeClass = mergeClasses(options.removeClass, remove);
5378         return $$animateQueue.push(element, 'setClass', options);
5379       },
5380
5381       /**
5382        * @ngdoc method
5383        * @name $animate#animate
5384        * @kind function
5385        *
5386        * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5387        * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5388        * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5389        * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5390        * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5391        *
5392        * @param {DOMElement} element the element which the CSS styles will be applied to
5393        * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5394        * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5395        * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5396        *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5397        *    (Note that if no animation is detected then this value will not be appplied to the element.)
5398        * @param {object=} options an optional collection of options/styles that will be applied to the element
5399        *
5400        * @return {Promise} the animation callback promise
5401        */
5402       animate: function(element, from, to, className, options) {
5403         options = prepareAnimateOptions(options);
5404         options.from = options.from ? extend(options.from, from) : from;
5405         options.to   = options.to   ? extend(options.to, to)     : to;
5406
5407         className = className || 'ng-inline-animate';
5408         options.tempClasses = mergeClasses(options.tempClasses, className);
5409         return $$animateQueue.push(element, 'animate', options);
5410       }
5411     };
5412   }];
5413 }];
5414
5415 /**
5416  * @ngdoc service
5417  * @name $animateCss
5418  * @kind object
5419  *
5420  * @description
5421  * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
5422  * then the `$animateCss` service will actually perform animations.
5423  *
5424  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5425  */
5426 var $CoreAnimateCssProvider = function() {
5427   this.$get = ['$$rAF', '$q', function($$rAF, $q) {
5428
5429     var RAFPromise = function() {};
5430     RAFPromise.prototype = {
5431       done: function(cancel) {
5432         this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
5433       },
5434       end: function() {
5435         this.done();
5436       },
5437       cancel: function() {
5438         this.done(true);
5439       },
5440       getPromise: function() {
5441         if (!this.defer) {
5442           this.defer = $q.defer();
5443         }
5444         return this.defer.promise;
5445       },
5446       then: function(f1,f2) {
5447         return this.getPromise().then(f1,f2);
5448       },
5449       'catch': function(f1) {
5450         return this.getPromise()['catch'](f1);
5451       },
5452       'finally': function(f1) {
5453         return this.getPromise()['finally'](f1);
5454       }
5455     };
5456
5457     return function(element, options) {
5458       // there is no point in applying the styles since
5459       // there is no animation that goes on at all in
5460       // this version of $animateCss.
5461       if (options.cleanupStyles) {
5462         options.from = options.to = null;
5463       }
5464
5465       if (options.from) {
5466         element.css(options.from);
5467         options.from = null;
5468       }
5469
5470       var closed, runner = new RAFPromise();
5471       return {
5472         start: run,
5473         end: run
5474       };
5475
5476       function run() {
5477         $$rAF(function() {
5478           close();
5479           if (!closed) {
5480             runner.done();
5481           }
5482           closed = true;
5483         });
5484         return runner;
5485       }
5486
5487       function close() {
5488         if (options.addClass) {
5489           element.addClass(options.addClass);
5490           options.addClass = null;
5491         }
5492         if (options.removeClass) {
5493           element.removeClass(options.removeClass);
5494           options.removeClass = null;
5495         }
5496         if (options.to) {
5497           element.css(options.to);
5498           options.to = null;
5499         }
5500       }
5501     };
5502   }];
5503 };
5504
5505 /* global stripHash: true */
5506
5507 /**
5508  * ! This is a private undocumented service !
5509  *
5510  * @name $browser
5511  * @requires $log
5512  * @description
5513  * This object has two goals:
5514  *
5515  * - hide all the global state in the browser caused by the window object
5516  * - abstract away all the browser specific features and inconsistencies
5517  *
5518  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
5519  * service, which can be used for convenient testing of the application without the interaction with
5520  * the real browser apis.
5521  */
5522 /**
5523  * @param {object} window The global window object.
5524  * @param {object} document jQuery wrapped document.
5525  * @param {object} $log window.console or an object with the same interface.
5526  * @param {object} $sniffer $sniffer service
5527  */
5528 function Browser(window, document, $log, $sniffer) {
5529   var self = this,
5530       rawDocument = document[0],
5531       location = window.location,
5532       history = window.history,
5533       setTimeout = window.setTimeout,
5534       clearTimeout = window.clearTimeout,
5535       pendingDeferIds = {};
5536
5537   self.isMock = false;
5538
5539   var outstandingRequestCount = 0;
5540   var outstandingRequestCallbacks = [];
5541
5542   // TODO(vojta): remove this temporary api
5543   self.$$completeOutstandingRequest = completeOutstandingRequest;
5544   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
5545
5546   /**
5547    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
5548    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
5549    */
5550   function completeOutstandingRequest(fn) {
5551     try {
5552       fn.apply(null, sliceArgs(arguments, 1));
5553     } finally {
5554       outstandingRequestCount--;
5555       if (outstandingRequestCount === 0) {
5556         while (outstandingRequestCallbacks.length) {
5557           try {
5558             outstandingRequestCallbacks.pop()();
5559           } catch (e) {
5560             $log.error(e);
5561           }
5562         }
5563       }
5564     }
5565   }
5566
5567   function getHash(url) {
5568     var index = url.indexOf('#');
5569     return index === -1 ? '' : url.substr(index);
5570   }
5571
5572   /**
5573    * @private
5574    * Note: this method is used only by scenario runner
5575    * TODO(vojta): prefix this method with $$ ?
5576    * @param {function()} callback Function that will be called when no outstanding request
5577    */
5578   self.notifyWhenNoOutstandingRequests = function(callback) {
5579     if (outstandingRequestCount === 0) {
5580       callback();
5581     } else {
5582       outstandingRequestCallbacks.push(callback);
5583     }
5584   };
5585
5586   //////////////////////////////////////////////////////////////
5587   // URL API
5588   //////////////////////////////////////////////////////////////
5589
5590   var cachedState, lastHistoryState,
5591       lastBrowserUrl = location.href,
5592       baseElement = document.find('base'),
5593       pendingLocation = null;
5594
5595   cacheState();
5596   lastHistoryState = cachedState;
5597
5598   /**
5599    * @name $browser#url
5600    *
5601    * @description
5602    * GETTER:
5603    * Without any argument, this method just returns current value of location.href.
5604    *
5605    * SETTER:
5606    * With at least one argument, this method sets url to new value.
5607    * If html5 history api supported, pushState/replaceState is used, otherwise
5608    * location.href/location.replace is used.
5609    * Returns its own instance to allow chaining
5610    *
5611    * NOTE: this api is intended for use only by the $location service. Please use the
5612    * {@link ng.$location $location service} to change url.
5613    *
5614    * @param {string} url New url (when used as setter)
5615    * @param {boolean=} replace Should new url replace current history record?
5616    * @param {object=} state object to use with pushState/replaceState
5617    */
5618   self.url = function(url, replace, state) {
5619     // In modern browsers `history.state` is `null` by default; treating it separately
5620     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5621     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5622     if (isUndefined(state)) {
5623       state = null;
5624     }
5625
5626     // Android Browser BFCache causes location, history reference to become stale.
5627     if (location !== window.location) location = window.location;
5628     if (history !== window.history) history = window.history;
5629
5630     // setter
5631     if (url) {
5632       var sameState = lastHistoryState === state;
5633
5634       // Don't change anything if previous and current URLs and states match. This also prevents
5635       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5636       // See https://github.com/angular/angular.js/commit/ffb2701
5637       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5638         return self;
5639       }
5640       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5641       lastBrowserUrl = url;
5642       lastHistoryState = state;
5643       // Don't use history API if only the hash changed
5644       // due to a bug in IE10/IE11 which leads
5645       // to not firing a `hashchange` nor `popstate` event
5646       // in some cases (see #9143).
5647       if ($sniffer.history && (!sameBase || !sameState)) {
5648         history[replace ? 'replaceState' : 'pushState'](state, '', url);
5649         cacheState();
5650         // Do the assignment again so that those two variables are referentially identical.
5651         lastHistoryState = cachedState;
5652       } else {
5653         if (!sameBase || pendingLocation) {
5654           pendingLocation = url;
5655         }
5656         if (replace) {
5657           location.replace(url);
5658         } else if (!sameBase) {
5659           location.href = url;
5660         } else {
5661           location.hash = getHash(url);
5662         }
5663         if (location.href !== url) {
5664           pendingLocation = url;
5665         }
5666       }
5667       return self;
5668     // getter
5669     } else {
5670       // - pendingLocation is needed as browsers don't allow to read out
5671       //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
5672       //   https://openradar.appspot.com/22186109).
5673       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5674       return pendingLocation || location.href.replace(/%27/g,"'");
5675     }
5676   };
5677
5678   /**
5679    * @name $browser#state
5680    *
5681    * @description
5682    * This method is a getter.
5683    *
5684    * Return history.state or null if history.state is undefined.
5685    *
5686    * @returns {object} state
5687    */
5688   self.state = function() {
5689     return cachedState;
5690   };
5691
5692   var urlChangeListeners = [],
5693       urlChangeInit = false;
5694
5695   function cacheStateAndFireUrlChange() {
5696     pendingLocation = null;
5697     cacheState();
5698     fireUrlChange();
5699   }
5700
5701   function getCurrentState() {
5702     try {
5703       return history.state;
5704     } catch (e) {
5705       // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5706     }
5707   }
5708
5709   // This variable should be used *only* inside the cacheState function.
5710   var lastCachedState = null;
5711   function cacheState() {
5712     // This should be the only place in $browser where `history.state` is read.
5713     cachedState = getCurrentState();
5714     cachedState = isUndefined(cachedState) ? null : cachedState;
5715
5716     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5717     if (equals(cachedState, lastCachedState)) {
5718       cachedState = lastCachedState;
5719     }
5720     lastCachedState = cachedState;
5721   }
5722
5723   function fireUrlChange() {
5724     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5725       return;
5726     }
5727
5728     lastBrowserUrl = self.url();
5729     lastHistoryState = cachedState;
5730     forEach(urlChangeListeners, function(listener) {
5731       listener(self.url(), cachedState);
5732     });
5733   }
5734
5735   /**
5736    * @name $browser#onUrlChange
5737    *
5738    * @description
5739    * Register callback function that will be called, when url changes.
5740    *
5741    * It's only called when the url is changed from outside of angular:
5742    * - user types different url into address bar
5743    * - user clicks on history (forward/back) button
5744    * - user clicks on a link
5745    *
5746    * It's not called when url is changed by $browser.url() method
5747    *
5748    * The listener gets called with new url as parameter.
5749    *
5750    * NOTE: this api is intended for use only by the $location service. Please use the
5751    * {@link ng.$location $location service} to monitor url changes in angular apps.
5752    *
5753    * @param {function(string)} listener Listener function to be called when url changes.
5754    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5755    */
5756   self.onUrlChange = function(callback) {
5757     // TODO(vojta): refactor to use node's syntax for events
5758     if (!urlChangeInit) {
5759       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5760       // don't fire popstate when user change the address bar and don't fire hashchange when url
5761       // changed by push/replaceState
5762
5763       // html5 history api - popstate event
5764       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5765       // hashchange event
5766       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5767
5768       urlChangeInit = true;
5769     }
5770
5771     urlChangeListeners.push(callback);
5772     return callback;
5773   };
5774
5775   /**
5776    * @private
5777    * Remove popstate and hashchange handler from window.
5778    *
5779    * NOTE: this api is intended for use only by $rootScope.
5780    */
5781   self.$$applicationDestroyed = function() {
5782     jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
5783   };
5784
5785   /**
5786    * Checks whether the url has changed outside of Angular.
5787    * Needs to be exported to be able to check for changes that have been done in sync,
5788    * as hashchange/popstate events fire in async.
5789    */
5790   self.$$checkUrlChange = fireUrlChange;
5791
5792   //////////////////////////////////////////////////////////////
5793   // Misc API
5794   //////////////////////////////////////////////////////////////
5795
5796   /**
5797    * @name $browser#baseHref
5798    *
5799    * @description
5800    * Returns current <base href>
5801    * (always relative - without domain)
5802    *
5803    * @returns {string} The current base href
5804    */
5805   self.baseHref = function() {
5806     var href = baseElement.attr('href');
5807     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5808   };
5809
5810   /**
5811    * @name $browser#defer
5812    * @param {function()} fn A function, who's execution should be deferred.
5813    * @param {number=} [delay=0] of milliseconds to defer the function execution.
5814    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5815    *
5816    * @description
5817    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5818    *
5819    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5820    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5821    * via `$browser.defer.flush()`.
5822    *
5823    */
5824   self.defer = function(fn, delay) {
5825     var timeoutId;
5826     outstandingRequestCount++;
5827     timeoutId = setTimeout(function() {
5828       delete pendingDeferIds[timeoutId];
5829       completeOutstandingRequest(fn);
5830     }, delay || 0);
5831     pendingDeferIds[timeoutId] = true;
5832     return timeoutId;
5833   };
5834
5835
5836   /**
5837    * @name $browser#defer.cancel
5838    *
5839    * @description
5840    * Cancels a deferred task identified with `deferId`.
5841    *
5842    * @param {*} deferId Token returned by the `$browser.defer` function.
5843    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5844    *                    canceled.
5845    */
5846   self.defer.cancel = function(deferId) {
5847     if (pendingDeferIds[deferId]) {
5848       delete pendingDeferIds[deferId];
5849       clearTimeout(deferId);
5850       completeOutstandingRequest(noop);
5851       return true;
5852     }
5853     return false;
5854   };
5855
5856 }
5857
5858 function $BrowserProvider() {
5859   this.$get = ['$window', '$log', '$sniffer', '$document',
5860       function($window, $log, $sniffer, $document) {
5861         return new Browser($window, $document, $log, $sniffer);
5862       }];
5863 }
5864
5865 /**
5866  * @ngdoc service
5867  * @name $cacheFactory
5868  *
5869  * @description
5870  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5871  * them.
5872  *
5873  * ```js
5874  *
5875  *  var cache = $cacheFactory('cacheId');
5876  *  expect($cacheFactory.get('cacheId')).toBe(cache);
5877  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5878  *
5879  *  cache.put("key", "value");
5880  *  cache.put("another key", "another value");
5881  *
5882  *  // We've specified no options on creation
5883  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5884  *
5885  * ```
5886  *
5887  *
5888  * @param {string} cacheId Name or id of the newly created cache.
5889  * @param {object=} options Options object that specifies the cache behavior. Properties:
5890  *
5891  *   - `{number=}` `capacity` — turns the cache into LRU cache.
5892  *
5893  * @returns {object} Newly created cache object with the following set of methods:
5894  *
5895  * - `{object}` `info()` — Returns id, size, and options of cache.
5896  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5897  *   it.
5898  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5899  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5900  * - `{void}` `removeAll()` — Removes all cached values.
5901  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5902  *
5903  * @example
5904    <example module="cacheExampleApp">
5905      <file name="index.html">
5906        <div ng-controller="CacheController">
5907          <input ng-model="newCacheKey" placeholder="Key">
5908          <input ng-model="newCacheValue" placeholder="Value">
5909          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5910
5911          <p ng-if="keys.length">Cached Values</p>
5912          <div ng-repeat="key in keys">
5913            <span ng-bind="key"></span>
5914            <span>: </span>
5915            <b ng-bind="cache.get(key)"></b>
5916          </div>
5917
5918          <p>Cache Info</p>
5919          <div ng-repeat="(key, value) in cache.info()">
5920            <span ng-bind="key"></span>
5921            <span>: </span>
5922            <b ng-bind="value"></b>
5923          </div>
5924        </div>
5925      </file>
5926      <file name="script.js">
5927        angular.module('cacheExampleApp', []).
5928          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
5929            $scope.keys = [];
5930            $scope.cache = $cacheFactory('cacheId');
5931            $scope.put = function(key, value) {
5932              if (angular.isUndefined($scope.cache.get(key))) {
5933                $scope.keys.push(key);
5934              }
5935              $scope.cache.put(key, angular.isUndefined(value) ? null : value);
5936            };
5937          }]);
5938      </file>
5939      <file name="style.css">
5940        p {
5941          margin: 10px 0 3px;
5942        }
5943      </file>
5944    </example>
5945  */
5946 function $CacheFactoryProvider() {
5947
5948   this.$get = function() {
5949     var caches = {};
5950
5951     function cacheFactory(cacheId, options) {
5952       if (cacheId in caches) {
5953         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
5954       }
5955
5956       var size = 0,
5957           stats = extend({}, options, {id: cacheId}),
5958           data = createMap(),
5959           capacity = (options && options.capacity) || Number.MAX_VALUE,
5960           lruHash = createMap(),
5961           freshEnd = null,
5962           staleEnd = null;
5963
5964       /**
5965        * @ngdoc type
5966        * @name $cacheFactory.Cache
5967        *
5968        * @description
5969        * A cache object used to store and retrieve data, primarily used by
5970        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
5971        * templates and other data.
5972        *
5973        * ```js
5974        *  angular.module('superCache')
5975        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
5976        *      return $cacheFactory('super-cache');
5977        *    }]);
5978        * ```
5979        *
5980        * Example test:
5981        *
5982        * ```js
5983        *  it('should behave like a cache', inject(function(superCache) {
5984        *    superCache.put('key', 'value');
5985        *    superCache.put('another key', 'another value');
5986        *
5987        *    expect(superCache.info()).toEqual({
5988        *      id: 'super-cache',
5989        *      size: 2
5990        *    });
5991        *
5992        *    superCache.remove('another key');
5993        *    expect(superCache.get('another key')).toBeUndefined();
5994        *
5995        *    superCache.removeAll();
5996        *    expect(superCache.info()).toEqual({
5997        *      id: 'super-cache',
5998        *      size: 0
5999        *    });
6000        *  }));
6001        * ```
6002        */
6003       return caches[cacheId] = {
6004
6005         /**
6006          * @ngdoc method
6007          * @name $cacheFactory.Cache#put
6008          * @kind function
6009          *
6010          * @description
6011          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
6012          * retrieved later, and incrementing the size of the cache if the key was not already
6013          * present in the cache. If behaving like an LRU cache, it will also remove stale
6014          * entries from the set.
6015          *
6016          * It will not insert undefined values into the cache.
6017          *
6018          * @param {string} key the key under which the cached data is stored.
6019          * @param {*} value the value to store alongside the key. If it is undefined, the key
6020          *    will not be stored.
6021          * @returns {*} the value stored.
6022          */
6023         put: function(key, value) {
6024           if (isUndefined(value)) return;
6025           if (capacity < Number.MAX_VALUE) {
6026             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
6027
6028             refresh(lruEntry);
6029           }
6030
6031           if (!(key in data)) size++;
6032           data[key] = value;
6033
6034           if (size > capacity) {
6035             this.remove(staleEnd.key);
6036           }
6037
6038           return value;
6039         },
6040
6041         /**
6042          * @ngdoc method
6043          * @name $cacheFactory.Cache#get
6044          * @kind function
6045          *
6046          * @description
6047          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
6048          *
6049          * @param {string} key the key of the data to be retrieved
6050          * @returns {*} the value stored.
6051          */
6052         get: function(key) {
6053           if (capacity < Number.MAX_VALUE) {
6054             var lruEntry = lruHash[key];
6055
6056             if (!lruEntry) return;
6057
6058             refresh(lruEntry);
6059           }
6060
6061           return data[key];
6062         },
6063
6064
6065         /**
6066          * @ngdoc method
6067          * @name $cacheFactory.Cache#remove
6068          * @kind function
6069          *
6070          * @description
6071          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
6072          *
6073          * @param {string} key the key of the entry to be removed
6074          */
6075         remove: function(key) {
6076           if (capacity < Number.MAX_VALUE) {
6077             var lruEntry = lruHash[key];
6078
6079             if (!lruEntry) return;
6080
6081             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
6082             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
6083             link(lruEntry.n,lruEntry.p);
6084
6085             delete lruHash[key];
6086           }
6087
6088           if (!(key in data)) return;
6089
6090           delete data[key];
6091           size--;
6092         },
6093
6094
6095         /**
6096          * @ngdoc method
6097          * @name $cacheFactory.Cache#removeAll
6098          * @kind function
6099          *
6100          * @description
6101          * Clears the cache object of any entries.
6102          */
6103         removeAll: function() {
6104           data = createMap();
6105           size = 0;
6106           lruHash = createMap();
6107           freshEnd = staleEnd = null;
6108         },
6109
6110
6111         /**
6112          * @ngdoc method
6113          * @name $cacheFactory.Cache#destroy
6114          * @kind function
6115          *
6116          * @description
6117          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
6118          * removing it from the {@link $cacheFactory $cacheFactory} set.
6119          */
6120         destroy: function() {
6121           data = null;
6122           stats = null;
6123           lruHash = null;
6124           delete caches[cacheId];
6125         },
6126
6127
6128         /**
6129          * @ngdoc method
6130          * @name $cacheFactory.Cache#info
6131          * @kind function
6132          *
6133          * @description
6134          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
6135          *
6136          * @returns {object} an object with the following properties:
6137          *   <ul>
6138          *     <li>**id**: the id of the cache instance</li>
6139          *     <li>**size**: the number of entries kept in the cache instance</li>
6140          *     <li>**...**: any additional properties from the options object when creating the
6141          *       cache.</li>
6142          *   </ul>
6143          */
6144         info: function() {
6145           return extend({}, stats, {size: size});
6146         }
6147       };
6148
6149
6150       /**
6151        * makes the `entry` the freshEnd of the LRU linked list
6152        */
6153       function refresh(entry) {
6154         if (entry != freshEnd) {
6155           if (!staleEnd) {
6156             staleEnd = entry;
6157           } else if (staleEnd == entry) {
6158             staleEnd = entry.n;
6159           }
6160
6161           link(entry.n, entry.p);
6162           link(entry, freshEnd);
6163           freshEnd = entry;
6164           freshEnd.n = null;
6165         }
6166       }
6167
6168
6169       /**
6170        * bidirectionally links two entries of the LRU linked list
6171        */
6172       function link(nextEntry, prevEntry) {
6173         if (nextEntry != prevEntry) {
6174           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
6175           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
6176         }
6177       }
6178     }
6179
6180
6181   /**
6182    * @ngdoc method
6183    * @name $cacheFactory#info
6184    *
6185    * @description
6186    * Get information about all the caches that have been created
6187    *
6188    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6189    */
6190     cacheFactory.info = function() {
6191       var info = {};
6192       forEach(caches, function(cache, cacheId) {
6193         info[cacheId] = cache.info();
6194       });
6195       return info;
6196     };
6197
6198
6199   /**
6200    * @ngdoc method
6201    * @name $cacheFactory#get
6202    *
6203    * @description
6204    * Get access to a cache object by the `cacheId` used when it was created.
6205    *
6206    * @param {string} cacheId Name or id of a cache to access.
6207    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6208    */
6209     cacheFactory.get = function(cacheId) {
6210       return caches[cacheId];
6211     };
6212
6213
6214     return cacheFactory;
6215   };
6216 }
6217
6218 /**
6219  * @ngdoc service
6220  * @name $templateCache
6221  *
6222  * @description
6223  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6224  * can load templates directly into the cache in a `script` tag, or by consuming the
6225  * `$templateCache` service directly.
6226  *
6227  * Adding via the `script` tag:
6228  *
6229  * ```html
6230  *   <script type="text/ng-template" id="templateId.html">
6231  *     <p>This is the content of the template</p>
6232  *   </script>
6233  * ```
6234  *
6235  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6236  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6237  * element with ng-app attribute), otherwise the template will be ignored.
6238  *
6239  * Adding via the `$templateCache` service:
6240  *
6241  * ```js
6242  * var myApp = angular.module('myApp', []);
6243  * myApp.run(function($templateCache) {
6244  *   $templateCache.put('templateId.html', 'This is the content of the template');
6245  * });
6246  * ```
6247  *
6248  * To retrieve the template later, simply use it in your HTML:
6249  * ```html
6250  * <div ng-include=" 'templateId.html' "></div>
6251  * ```
6252  *
6253  * or get it via Javascript:
6254  * ```js
6255  * $templateCache.get('templateId.html')
6256  * ```
6257  *
6258  * See {@link ng.$cacheFactory $cacheFactory}.
6259  *
6260  */
6261 function $TemplateCacheProvider() {
6262   this.$get = ['$cacheFactory', function($cacheFactory) {
6263     return $cacheFactory('templates');
6264   }];
6265 }
6266
6267 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6268  *     Any commits to this file should be reviewed with security in mind.  *
6269  *   Changes to this file can potentially create security vulnerabilities. *
6270  *          An approval from 2 Core members with history of modifying      *
6271  *                         this file is required.                          *
6272  *                                                                         *
6273  *  Does the change somehow allow for arbitrary javascript to be executed? *
6274  *    Or allows for someone to change the prototype of built-in objects?   *
6275  *     Or gives undesired access to variables likes document or window?    *
6276  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6277
6278 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6279  *
6280  * DOM-related variables:
6281  *
6282  * - "node" - DOM Node
6283  * - "element" - DOM Element or Node
6284  * - "$node" or "$element" - jqLite-wrapped node or element
6285  *
6286  *
6287  * Compiler related stuff:
6288  *
6289  * - "linkFn" - linking fn of a single directive
6290  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6291  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6292  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6293  */
6294
6295
6296 /**
6297  * @ngdoc service
6298  * @name $compile
6299  * @kind function
6300  *
6301  * @description
6302  * Compiles an HTML string or DOM into a template and produces a template function, which
6303  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6304  *
6305  * The compilation is a process of walking the DOM tree and matching DOM elements to
6306  * {@link ng.$compileProvider#directive directives}.
6307  *
6308  * <div class="alert alert-warning">
6309  * **Note:** This document is an in-depth reference of all directive options.
6310  * For a gentle introduction to directives with examples of common use cases,
6311  * see the {@link guide/directive directive guide}.
6312  * </div>
6313  *
6314  * ## Comprehensive Directive API
6315  *
6316  * There are many different options for a directive.
6317  *
6318  * The difference resides in the return value of the factory function.
6319  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
6320  * or just the `postLink` function (all other properties will have the default values).
6321  *
6322  * <div class="alert alert-success">
6323  * **Best Practice:** It's recommended to use the "directive definition object" form.
6324  * </div>
6325  *
6326  * Here's an example directive declared with a Directive Definition Object:
6327  *
6328  * ```js
6329  *   var myModule = angular.module(...);
6330  *
6331  *   myModule.directive('directiveName', function factory(injectables) {
6332  *     var directiveDefinitionObject = {
6333  *       priority: 0,
6334  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
6335  *       // or
6336  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
6337  *       transclude: false,
6338  *       restrict: 'A',
6339  *       templateNamespace: 'html',
6340  *       scope: false,
6341  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6342  *       controllerAs: 'stringIdentifier',
6343  *       bindToController: false,
6344  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6345  *       compile: function compile(tElement, tAttrs, transclude) {
6346  *         return {
6347  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6348  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
6349  *         }
6350  *         // or
6351  *         // return function postLink( ... ) { ... }
6352  *       },
6353  *       // or
6354  *       // link: {
6355  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6356  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
6357  *       // }
6358  *       // or
6359  *       // link: function postLink( ... ) { ... }
6360  *     };
6361  *     return directiveDefinitionObject;
6362  *   });
6363  * ```
6364  *
6365  * <div class="alert alert-warning">
6366  * **Note:** Any unspecified options will use the default value. You can see the default values below.
6367  * </div>
6368  *
6369  * Therefore the above can be simplified as:
6370  *
6371  * ```js
6372  *   var myModule = angular.module(...);
6373  *
6374  *   myModule.directive('directiveName', function factory(injectables) {
6375  *     var directiveDefinitionObject = {
6376  *       link: function postLink(scope, iElement, iAttrs) { ... }
6377  *     };
6378  *     return directiveDefinitionObject;
6379  *     // or
6380  *     // return function postLink(scope, iElement, iAttrs) { ... }
6381  *   });
6382  * ```
6383  *
6384  *
6385  *
6386  * ### Directive Definition Object
6387  *
6388  * The directive definition object provides instructions to the {@link ng.$compile
6389  * compiler}. The attributes are:
6390  *
6391  * #### `multiElement`
6392  * When this property is set to true, the HTML compiler will collect DOM nodes between
6393  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6394  * together as the directive elements. It is recommended that this feature be used on directives
6395  * which are not strictly behavioural (such as {@link ngClick}), and which
6396  * do not manipulate or replace child nodes (such as {@link ngInclude}).
6397  *
6398  * #### `priority`
6399  * When there are multiple directives defined on a single DOM element, sometimes it
6400  * is necessary to specify the order in which the directives are applied. The `priority` is used
6401  * to sort the directives before their `compile` functions get called. Priority is defined as a
6402  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
6403  * are also run in priority order, but post-link functions are run in reverse order. The order
6404  * of directives with the same priority is undefined. The default priority is `0`.
6405  *
6406  * #### `terminal`
6407  * If set to true then the current `priority` will be the last set of directives
6408  * which will execute (any directives at the current priority will still execute
6409  * as the order of execution on same `priority` is undefined). Note that expressions
6410  * and other directives used in the directive's template will also be excluded from execution.
6411  *
6412  * #### `scope`
6413  * The scope property can be `true`, an object or a falsy value:
6414  *
6415  * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
6416  *
6417  * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
6418  * the directive's element. If multiple directives on the same element request a new scope,
6419  * only one new scope is created. The new scope rule does not apply for the root of the template
6420  * since the root of the template always gets a new scope.
6421  *
6422  * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
6423  * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
6424  * scope. This is useful when creating reusable components, which should not accidentally read or modify
6425  * data in the parent scope.
6426  *
6427  * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
6428  * directive's element. These local properties are useful for aliasing values for templates. The keys in
6429  * the object hash map to the name of the property on the isolate scope; the values define how the property
6430  * is bound to the parent scope, via matching attributes on the directive's element:
6431  *
6432  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6433  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
6434  *   attribute name is assumed to be the same as the local name.
6435  *   Given `<widget my-attr="hello {{name}}">` and widget definition
6436  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6437  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6438  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
6439  *   component scope).
6440  *
6441  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6442  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6443  *   name is specified then the attribute name is assumed to be the same as the local name.
6444  *   Given `<widget my-attr="parentModel">` and widget definition of
6445  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6446  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6447  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6448  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6449  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6450  *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6451  *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6452  *
6453  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6454  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
6455  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
6456  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6457  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
6458  *   pass data from the isolated scope via an expression to the parent scope, this can be
6459  *   done by passing a map of local variable names and values into the expression wrapper fn.
6460  *   For example, if the expression is `increment(amount)` then we can specify the amount value
6461  *   by calling the `localFn` as `localFn({amount: 22})`.
6462  *
6463  * In general it's possible to apply more than one directive to one element, but there might be limitations
6464  * depending on the type of scope required by the directives. The following points will help explain these limitations.
6465  * For simplicity only two directives are taken into account, but it is also applicable for several directives:
6466  *
6467  * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
6468  * * **child scope** + **no scope** =>  Both directives will share one single child scope
6469  * * **child scope** + **child scope** =>  Both directives will share one single child scope
6470  * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
6471  * its parent's scope
6472  * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
6473  * be applied to the same element.
6474  * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
6475  * cannot be applied to the same element.
6476  *
6477  *
6478  * #### `bindToController`
6479  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6480  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6481  * is instantiated, the initial values of the isolate scope bindings are already available.
6482  *
6483  * #### `controller`
6484  * Controller constructor function. The controller is instantiated before the
6485  * pre-linking phase and can be accessed by other directives (see
6486  * `require` attribute). This allows the directives to communicate with each other and augment
6487  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
6488  *
6489  * * `$scope` - Current scope associated with the element
6490  * * `$element` - Current element
6491  * * `$attrs` - Current attributes object for the element
6492  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6493  *   `function([scope], cloneLinkingFn, futureParentElement)`.
6494  *    * `scope`: optional argument to override the scope.
6495  *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6496  *    * `futureParentElement`:
6497  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6498  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6499  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
6500  *          and when the `cloneLinkinFn` is passed,
6501  *          as those elements need to created and cloned in a special way when they are defined outside their
6502  *          usual containers (e.g. like `<svg>`).
6503  *        * See also the `directive.templateNamespace` property.
6504  *
6505  *
6506  * #### `require`
6507  * Require another directive and inject its controller as the fourth argument to the linking function. The
6508  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6509  * injected argument will be an array in corresponding order. If no such directive can be
6510  * found, or if the directive does not have a controller, then an error is raised (unless no link function
6511  * is specified, in which case error checking is skipped). The name can be prefixed with:
6512  *
6513  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6514  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
6515  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
6516  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
6517  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
6518  *   `null` to the `link` fn if not found.
6519  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
6520  *   `null` to the `link` fn if not found.
6521  *
6522  *
6523  * #### `controllerAs`
6524  * Identifier name for a reference to the controller in the directive's scope.
6525  * This allows the controller to be referenced from the directive template. This is especially
6526  * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
6527  * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
6528  * `controllerAs` reference might overwrite a property that already exists on the parent scope.
6529  *
6530  *
6531  * #### `restrict`
6532  * String of subset of `EACM` which restricts the directive to a specific directive
6533  * declaration style. If omitted, the defaults (elements and attributes) are used.
6534  *
6535  * * `E` - Element name (default): `<my-directive></my-directive>`
6536  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6537  * * `C` - Class: `<div class="my-directive: exp;"></div>`
6538  * * `M` - Comment: `<!-- directive: my-directive exp -->`
6539  *
6540  *
6541  * #### `templateNamespace`
6542  * String representing the document type used by the markup in the template.
6543  * AngularJS needs this information as those elements need to be created and cloned
6544  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6545  *
6546  * * `html` - All root nodes in the template are HTML. Root nodes may also be
6547  *   top-level elements such as `<svg>` or `<math>`.
6548  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6549  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6550  *
6551  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6552  *
6553  * #### `template`
6554  * HTML markup that may:
6555  * * Replace the contents of the directive's element (default).
6556  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6557  * * Wrap the contents of the directive's element (if `transclude` is true).
6558  *
6559  * Value may be:
6560  *
6561  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6562  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6563  *   function api below) and returns a string value.
6564  *
6565  *
6566  * #### `templateUrl`
6567  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6568  *
6569  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6570  * for later when the template has been resolved.  In the meantime it will continue to compile and link
6571  * sibling and parent elements as though this element had not contained any directives.
6572  *
6573  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6574  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6575  * case when only one deeply nested directive has `templateUrl`.
6576  *
6577  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6578  *
6579  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6580  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6581  * a string value representing the url.  In either case, the template URL is passed through {@link
6582  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6583  *
6584  *
6585  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6586  * specify what the template should replace. Defaults to `false`.
6587  *
6588  * * `true` - the template will replace the directive's element.
6589  * * `false` - the template will replace the contents of the directive's element.
6590  *
6591  * The replacement process migrates all of the attributes / classes from the old element to the new
6592  * one. See the {@link guide/directive#template-expanding-directive
6593  * Directives Guide} for an example.
6594  *
6595  * There are very few scenarios where element replacement is required for the application function,
6596  * the main one being reusable custom components that are used within SVG contexts
6597  * (because SVG doesn't work with custom elements in the DOM tree).
6598  *
6599  * #### `transclude`
6600  * Extract the contents of the element where the directive appears and make it available to the directive.
6601  * The contents are compiled and provided to the directive as a **transclusion function**. See the
6602  * {@link $compile#transclusion Transclusion} section below.
6603  *
6604  * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6605  * directive's element or the entire element:
6606  *
6607  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6608  * * `'element'` - transclude the whole of the directive's element including any directives on this
6609  *   element that defined at a lower priority than this directive. When used, the `template`
6610  *   property is ignored.
6611  *
6612  *
6613  * #### `compile`
6614  *
6615  * ```js
6616  *   function compile(tElement, tAttrs, transclude) { ... }
6617  * ```
6618  *
6619  * The compile function deals with transforming the template DOM. Since most directives do not do
6620  * template transformation, it is not used often. The compile function takes the following arguments:
6621  *
6622  *   * `tElement` - template element - The element where the directive has been declared. It is
6623  *     safe to do template transformation on the element and child elements only.
6624  *
6625  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6626  *     between all directive compile functions.
6627  *
6628  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6629  *
6630  * <div class="alert alert-warning">
6631  * **Note:** The template instance and the link instance may be different objects if the template has
6632  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6633  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6634  * should be done in a linking function rather than in a compile function.
6635  * </div>
6636
6637  * <div class="alert alert-warning">
6638  * **Note:** The compile function cannot handle directives that recursively use themselves in their
6639  * own templates or compile functions. Compiling these directives results in an infinite loop and a
6640  * stack overflow errors.
6641  *
6642  * This can be avoided by manually using $compile in the postLink function to imperatively compile
6643  * a directive's template instead of relying on automatic template compilation via `template` or
6644  * `templateUrl` declaration or manual compilation inside the compile function.
6645  * </div>
6646  *
6647  * <div class="alert alert-danger">
6648  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6649  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6650  *   to the link function instead.
6651  * </div>
6652
6653  * A compile function can have a return value which can be either a function or an object.
6654  *
6655  * * returning a (post-link) function - is equivalent to registering the linking function via the
6656  *   `link` property of the config object when the compile function is empty.
6657  *
6658  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6659  *   control when a linking function should be called during the linking phase. See info about
6660  *   pre-linking and post-linking functions below.
6661  *
6662  *
6663  * #### `link`
6664  * This property is used only if the `compile` property is not defined.
6665  *
6666  * ```js
6667  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6668  * ```
6669  *
6670  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6671  * executed after the template has been cloned. This is where most of the directive logic will be
6672  * put.
6673  *
6674  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6675  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6676  *
6677  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6678  *     manipulate the children of the element only in `postLink` function since the children have
6679  *     already been linked.
6680  *
6681  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6682  *     between all directive linking functions.
6683  *
6684  *   * `controller` - the directive's required controller instance(s) - Instances are shared
6685  *     among all directives, which allows the directives to use the controllers as a communication
6686  *     channel. The exact value depends on the directive's `require` property:
6687  *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
6688  *       * `string`: the controller instance
6689  *       * `array`: array of controller instances
6690  *
6691  *     If a required controller cannot be found, and it is optional, the instance is `null`,
6692  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6693  *
6694  *     Note that you can also require the directive's own controller - it will be made available like
6695  *     any other controller.
6696  *
6697  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6698  *     This is the same as the `$transclude`
6699  *     parameter of directive controllers, see there for details.
6700  *     `function([scope], cloneLinkingFn, futureParentElement)`.
6701  *
6702  * #### Pre-linking function
6703  *
6704  * Executed before the child elements are linked. Not safe to do DOM transformation since the
6705  * compiler linking function will fail to locate the correct elements for linking.
6706  *
6707  * #### Post-linking function
6708  *
6709  * Executed after the child elements are linked.
6710  *
6711  * Note that child elements that contain `templateUrl` directives will not have been compiled
6712  * and linked since they are waiting for their template to load asynchronously and their own
6713  * compilation and linking has been suspended until that occurs.
6714  *
6715  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6716  * for their async templates to be resolved.
6717  *
6718  *
6719  * ### Transclusion
6720  *
6721  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
6722  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6723  * scope from where they were taken.
6724  *
6725  * Transclusion is used (often with {@link ngTransclude}) to insert the
6726  * original contents of a directive's element into a specified place in the template of the directive.
6727  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6728  * content has access to the properties on the scope from which it was taken, even if the directive
6729  * has isolated scope.
6730  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6731  *
6732  * This makes it possible for the widget to have private state for its template, while the transcluded
6733  * content has access to its originating scope.
6734  *
6735  * <div class="alert alert-warning">
6736  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6737  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6738  * Testing Transclusion Directives}.
6739  * </div>
6740  *
6741  * #### Transclusion Functions
6742  *
6743  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6744  * function** to the directive's `link` function and `controller`. This transclusion function is a special
6745  * **linking function** that will return the compiled contents linked to a new transclusion scope.
6746  *
6747  * <div class="alert alert-info">
6748  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6749  * ngTransclude will deal with it for us.
6750  * </div>
6751  *
6752  * If you want to manually control the insertion and removal of the transcluded content in your directive
6753  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6754  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6755  *
6756  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6757  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6758  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6759  *
6760  * <div class="alert alert-info">
6761  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6762  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6763  * </div>
6764  *
6765  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6766  * attach function**:
6767  *
6768  * ```js
6769  * var transcludedContent, transclusionScope;
6770  *
6771  * $transclude(function(clone, scope) {
6772  *   element.append(clone);
6773  *   transcludedContent = clone;
6774  *   transclusionScope = scope;
6775  * });
6776  * ```
6777  *
6778  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6779  * associated transclusion scope:
6780  *
6781  * ```js
6782  * transcludedContent.remove();
6783  * transclusionScope.$destroy();
6784  * ```
6785  *
6786  * <div class="alert alert-info">
6787  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6788  * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
6789  * then you are also responsible for calling `$destroy` on the transclusion scope.
6790  * </div>
6791  *
6792  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6793  * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6794  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6795  *
6796  *
6797  * #### Transclusion Scopes
6798  *
6799  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6800  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6801  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6802  * was taken.
6803  *
6804  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6805  * like this:
6806  *
6807  * ```html
6808  * <div ng-app>
6809  *   <div isolate>
6810  *     <div transclusion>
6811  *     </div>
6812  *   </div>
6813  * </div>
6814  * ```
6815  *
6816  * The `$parent` scope hierarchy will look like this:
6817  *
6818  * ```
6819  * - $rootScope
6820  *   - isolate
6821  *     - transclusion
6822  * ```
6823  *
6824  * but the scopes will inherit prototypically from different scopes to their `$parent`.
6825  *
6826  * ```
6827  * - $rootScope
6828  *   - transclusion
6829  * - isolate
6830  * ```
6831  *
6832  *
6833  * ### Attributes
6834  *
6835  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6836  * `link()` or `compile()` functions. It has a variety of uses.
6837  *
6838  * accessing *Normalized attribute names:*
6839  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6840  * the attributes object allows for normalized access to
6841  *   the attributes.
6842  *
6843  * * *Directive inter-communication:* All directives share the same instance of the attributes
6844  *   object which allows the directives to use the attributes object as inter directive
6845  *   communication.
6846  *
6847  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6848  *   allowing other directives to read the interpolated value.
6849  *
6850  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6851  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6852  *   the only way to easily get the actual value because during the linking phase the interpolation
6853  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6854  *
6855  * ```js
6856  * function linkingFn(scope, elm, attrs, ctrl) {
6857  *   // get the attribute value
6858  *   console.log(attrs.ngModel);
6859  *
6860  *   // change the attribute
6861  *   attrs.$set('ngModel', 'new value');
6862  *
6863  *   // observe changes to interpolated attribute
6864  *   attrs.$observe('ngModel', function(value) {
6865  *     console.log('ngModel has changed value to ' + value);
6866  *   });
6867  * }
6868  * ```
6869  *
6870  * ## Example
6871  *
6872  * <div class="alert alert-warning">
6873  * **Note**: Typically directives are registered with `module.directive`. The example below is
6874  * to illustrate how `$compile` works.
6875  * </div>
6876  *
6877  <example module="compileExample">
6878    <file name="index.html">
6879     <script>
6880       angular.module('compileExample', [], function($compileProvider) {
6881         // configure new 'compile' directive by passing a directive
6882         // factory function. The factory function injects the '$compile'
6883         $compileProvider.directive('compile', function($compile) {
6884           // directive factory creates a link function
6885           return function(scope, element, attrs) {
6886             scope.$watch(
6887               function(scope) {
6888                  // watch the 'compile' expression for changes
6889                 return scope.$eval(attrs.compile);
6890               },
6891               function(value) {
6892                 // when the 'compile' expression changes
6893                 // assign it into the current DOM
6894                 element.html(value);
6895
6896                 // compile the new DOM and link it to the current
6897                 // scope.
6898                 // NOTE: we only compile .childNodes so that
6899                 // we don't get into infinite loop compiling ourselves
6900                 $compile(element.contents())(scope);
6901               }
6902             );
6903           };
6904         });
6905       })
6906       .controller('GreeterController', ['$scope', function($scope) {
6907         $scope.name = 'Angular';
6908         $scope.html = 'Hello {{name}}';
6909       }]);
6910     </script>
6911     <div ng-controller="GreeterController">
6912       <input ng-model="name"> <br/>
6913       <textarea ng-model="html"></textarea> <br/>
6914       <div compile="html"></div>
6915     </div>
6916    </file>
6917    <file name="protractor.js" type="protractor">
6918      it('should auto compile', function() {
6919        var textarea = $('textarea');
6920        var output = $('div[compile]');
6921        // The initial state reads 'Hello Angular'.
6922        expect(output.getText()).toBe('Hello Angular');
6923        textarea.clear();
6924        textarea.sendKeys('{{name}}!');
6925        expect(output.getText()).toBe('Angular!');
6926      });
6927    </file>
6928  </example>
6929
6930  *
6931  *
6932  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
6933  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
6934  *
6935  * <div class="alert alert-danger">
6936  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
6937  *   e.g. will not use the right outer scope. Please pass the transclude function as a
6938  *   `parentBoundTranscludeFn` to the link function instead.
6939  * </div>
6940  *
6941  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
6942  *                 root element(s), not their children)
6943  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
6944  * (a DOM element/tree) to a scope. Where:
6945  *
6946  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
6947  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
6948  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
6949  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
6950  *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
6951  *
6952  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
6953  *      * `scope` - is the current scope with which the linking function is working with.
6954  *
6955  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
6956  *  keys may be used to control linking behavior:
6957  *
6958  *      * `parentBoundTranscludeFn` - the transclude function made available to
6959  *        directives; if given, it will be passed through to the link functions of
6960  *        directives found in `element` during compilation.
6961  *      * `transcludeControllers` - an object hash with keys that map controller names
6962  *        to controller instances; if given, it will make the controllers
6963  *        available to directives.
6964  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6965  *        the cloned elements; only needed for transcludes that are allowed to contain non html
6966  *        elements (e.g. SVG elements). See also the directive.controller property.
6967  *
6968  * Calling the linking function returns the element of the template. It is either the original
6969  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
6970  *
6971  * After linking the view is not updated until after a call to $digest which typically is done by
6972  * Angular automatically.
6973  *
6974  * If you need access to the bound view, there are two ways to do it:
6975  *
6976  * - If you are not asking the linking function to clone the template, create the DOM element(s)
6977  *   before you send them to the compiler and keep this reference around.
6978  *   ```js
6979  *     var element = $compile('<p>{{total}}</p>')(scope);
6980  *   ```
6981  *
6982  * - if on the other hand, you need the element to be cloned, the view reference from the original
6983  *   example would not point to the clone, but rather to the original template that was cloned. In
6984  *   this case, you can access the clone via the cloneAttachFn:
6985  *   ```js
6986  *     var templateElement = angular.element('<p>{{total}}</p>'),
6987  *         scope = ....;
6988  *
6989  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
6990  *       //attach the clone to DOM document at the right place
6991  *     });
6992  *
6993  *     //now we have reference to the cloned DOM via `clonedElement`
6994  *   ```
6995  *
6996  *
6997  * For information on how the compiler works, see the
6998  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
6999  */
7000
7001 var $compileMinErr = minErr('$compile');
7002
7003 /**
7004  * @ngdoc provider
7005  * @name $compileProvider
7006  *
7007  * @description
7008  */
7009 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
7010 function $CompileProvider($provide, $$sanitizeUriProvider) {
7011   var hasDirectives = {},
7012       Suffix = 'Directive',
7013       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
7014       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
7015       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
7016       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
7017
7018   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
7019   // The assumption is that future DOM event attribute names will begin with
7020   // 'on' and be composed of only English letters.
7021   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7022
7023   function parseIsolateBindings(scope, directiveName, isController) {
7024     var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
7025
7026     var bindings = {};
7027
7028     forEach(scope, function(definition, scopeName) {
7029       var match = definition.match(LOCAL_REGEXP);
7030
7031       if (!match) {
7032         throw $compileMinErr('iscp',
7033             "Invalid {3} for directive '{0}'." +
7034             " Definition: {... {1}: '{2}' ...}",
7035             directiveName, scopeName, definition,
7036             (isController ? "controller bindings definition" :
7037             "isolate scope definition"));
7038       }
7039
7040       bindings[scopeName] = {
7041         mode: match[1][0],
7042         collection: match[2] === '*',
7043         optional: match[3] === '?',
7044         attrName: match[4] || scopeName
7045       };
7046     });
7047
7048     return bindings;
7049   }
7050
7051   function parseDirectiveBindings(directive, directiveName) {
7052     var bindings = {
7053       isolateScope: null,
7054       bindToController: null
7055     };
7056     if (isObject(directive.scope)) {
7057       if (directive.bindToController === true) {
7058         bindings.bindToController = parseIsolateBindings(directive.scope,
7059                                                          directiveName, true);
7060         bindings.isolateScope = {};
7061       } else {
7062         bindings.isolateScope = parseIsolateBindings(directive.scope,
7063                                                      directiveName, false);
7064       }
7065     }
7066     if (isObject(directive.bindToController)) {
7067       bindings.bindToController =
7068           parseIsolateBindings(directive.bindToController, directiveName, true);
7069     }
7070     if (isObject(bindings.bindToController)) {
7071       var controller = directive.controller;
7072       var controllerAs = directive.controllerAs;
7073       if (!controller) {
7074         // There is no controller, there may or may not be a controllerAs property
7075         throw $compileMinErr('noctrl',
7076               "Cannot bind to controller without directive '{0}'s controller.",
7077               directiveName);
7078       } else if (!identifierForController(controller, controllerAs)) {
7079         // There is a controller, but no identifier or controllerAs property
7080         throw $compileMinErr('noident',
7081               "Cannot bind to controller without identifier for directive '{0}'.",
7082               directiveName);
7083       }
7084     }
7085     return bindings;
7086   }
7087
7088   function assertValidDirectiveName(name) {
7089     var letter = name.charAt(0);
7090     if (!letter || letter !== lowercase(letter)) {
7091       throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
7092     }
7093     if (name !== name.trim()) {
7094       throw $compileMinErr('baddir',
7095             "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7096             name);
7097     }
7098   }
7099
7100   /**
7101    * @ngdoc method
7102    * @name $compileProvider#directive
7103    * @kind function
7104    *
7105    * @description
7106    * Register a new directive with the compiler.
7107    *
7108    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7109    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7110    *    names and the values are the factories.
7111    * @param {Function|Array} directiveFactory An injectable directive factory function. See
7112    *    {@link guide/directive} for more info.
7113    * @returns {ng.$compileProvider} Self for chaining.
7114    */
7115    this.directive = function registerDirective(name, directiveFactory) {
7116     assertNotHasOwnProperty(name, 'directive');
7117     if (isString(name)) {
7118       assertValidDirectiveName(name);
7119       assertArg(directiveFactory, 'directiveFactory');
7120       if (!hasDirectives.hasOwnProperty(name)) {
7121         hasDirectives[name] = [];
7122         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
7123           function($injector, $exceptionHandler) {
7124             var directives = [];
7125             forEach(hasDirectives[name], function(directiveFactory, index) {
7126               try {
7127                 var directive = $injector.invoke(directiveFactory);
7128                 if (isFunction(directive)) {
7129                   directive = { compile: valueFn(directive) };
7130                 } else if (!directive.compile && directive.link) {
7131                   directive.compile = valueFn(directive.link);
7132                 }
7133                 directive.priority = directive.priority || 0;
7134                 directive.index = index;
7135                 directive.name = directive.name || name;
7136                 directive.require = directive.require || (directive.controller && directive.name);
7137                 directive.restrict = directive.restrict || 'EA';
7138                 var bindings = directive.$$bindings =
7139                     parseDirectiveBindings(directive, directive.name);
7140                 if (isObject(bindings.isolateScope)) {
7141                   directive.$$isolateBindings = bindings.isolateScope;
7142                 }
7143                 directive.$$moduleName = directiveFactory.$$moduleName;
7144                 directives.push(directive);
7145               } catch (e) {
7146                 $exceptionHandler(e);
7147               }
7148             });
7149             return directives;
7150           }]);
7151       }
7152       hasDirectives[name].push(directiveFactory);
7153     } else {
7154       forEach(name, reverseParams(registerDirective));
7155     }
7156     return this;
7157   };
7158
7159
7160   /**
7161    * @ngdoc method
7162    * @name $compileProvider#aHrefSanitizationWhitelist
7163    * @kind function
7164    *
7165    * @description
7166    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7167    * urls during a[href] sanitization.
7168    *
7169    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
7170    *
7171    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
7172    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
7173    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7174    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7175    *
7176    * @param {RegExp=} regexp New regexp to whitelist urls with.
7177    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7178    *    chaining otherwise.
7179    */
7180   this.aHrefSanitizationWhitelist = function(regexp) {
7181     if (isDefined(regexp)) {
7182       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
7183       return this;
7184     } else {
7185       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
7186     }
7187   };
7188
7189
7190   /**
7191    * @ngdoc method
7192    * @name $compileProvider#imgSrcSanitizationWhitelist
7193    * @kind function
7194    *
7195    * @description
7196    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7197    * urls during img[src] sanitization.
7198    *
7199    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
7200    *
7201    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
7202    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
7203    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7204    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7205    *
7206    * @param {RegExp=} regexp New regexp to whitelist urls with.
7207    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7208    *    chaining otherwise.
7209    */
7210   this.imgSrcSanitizationWhitelist = function(regexp) {
7211     if (isDefined(regexp)) {
7212       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
7213       return this;
7214     } else {
7215       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
7216     }
7217   };
7218
7219   /**
7220    * @ngdoc method
7221    * @name  $compileProvider#debugInfoEnabled
7222    *
7223    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
7224    * current debugInfoEnabled state
7225    * @returns {*} current value if used as getter or itself (chaining) if used as setter
7226    *
7227    * @kind function
7228    *
7229    * @description
7230    * Call this method to enable/disable various debug runtime information in the compiler such as adding
7231    * binding information and a reference to the current scope on to DOM elements.
7232    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
7233    * * `ng-binding` CSS class
7234    * * `$binding` data property containing an array of the binding expressions
7235    *
7236    * You may want to disable this in production for a significant performance boost. See
7237    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
7238    *
7239    * The default value is true.
7240    */
7241   var debugInfoEnabled = true;
7242   this.debugInfoEnabled = function(enabled) {
7243     if (isDefined(enabled)) {
7244       debugInfoEnabled = enabled;
7245       return this;
7246     }
7247     return debugInfoEnabled;
7248   };
7249
7250   this.$get = [
7251             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7252             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7253     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
7254              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
7255
7256     var Attributes = function(element, attributesToCopy) {
7257       if (attributesToCopy) {
7258         var keys = Object.keys(attributesToCopy);
7259         var i, l, key;
7260
7261         for (i = 0, l = keys.length; i < l; i++) {
7262           key = keys[i];
7263           this[key] = attributesToCopy[key];
7264         }
7265       } else {
7266         this.$attr = {};
7267       }
7268
7269       this.$$element = element;
7270     };
7271
7272     Attributes.prototype = {
7273       /**
7274        * @ngdoc method
7275        * @name $compile.directive.Attributes#$normalize
7276        * @kind function
7277        *
7278        * @description
7279        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
7280        * `data-`) to its normalized, camelCase form.
7281        *
7282        * Also there is special case for Moz prefix starting with upper case letter.
7283        *
7284        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7285        *
7286        * @param {string} name Name to normalize
7287        */
7288       $normalize: directiveNormalize,
7289
7290
7291       /**
7292        * @ngdoc method
7293        * @name $compile.directive.Attributes#$addClass
7294        * @kind function
7295        *
7296        * @description
7297        * Adds the CSS class value specified by the classVal parameter to the element. If animations
7298        * are enabled then an animation will be triggered for the class addition.
7299        *
7300        * @param {string} classVal The className value that will be added to the element
7301        */
7302       $addClass: function(classVal) {
7303         if (classVal && classVal.length > 0) {
7304           $animate.addClass(this.$$element, classVal);
7305         }
7306       },
7307
7308       /**
7309        * @ngdoc method
7310        * @name $compile.directive.Attributes#$removeClass
7311        * @kind function
7312        *
7313        * @description
7314        * Removes the CSS class value specified by the classVal parameter from the element. If
7315        * animations are enabled then an animation will be triggered for the class removal.
7316        *
7317        * @param {string} classVal The className value that will be removed from the element
7318        */
7319       $removeClass: function(classVal) {
7320         if (classVal && classVal.length > 0) {
7321           $animate.removeClass(this.$$element, classVal);
7322         }
7323       },
7324
7325       /**
7326        * @ngdoc method
7327        * @name $compile.directive.Attributes#$updateClass
7328        * @kind function
7329        *
7330        * @description
7331        * Adds and removes the appropriate CSS class values to the element based on the difference
7332        * between the new and old CSS class values (specified as newClasses and oldClasses).
7333        *
7334        * @param {string} newClasses The current CSS className value
7335        * @param {string} oldClasses The former CSS className value
7336        */
7337       $updateClass: function(newClasses, oldClasses) {
7338         var toAdd = tokenDifference(newClasses, oldClasses);
7339         if (toAdd && toAdd.length) {
7340           $animate.addClass(this.$$element, toAdd);
7341         }
7342
7343         var toRemove = tokenDifference(oldClasses, newClasses);
7344         if (toRemove && toRemove.length) {
7345           $animate.removeClass(this.$$element, toRemove);
7346         }
7347       },
7348
7349       /**
7350        * Set a normalized attribute on the element in a way such that all directives
7351        * can share the attribute. This function properly handles boolean attributes.
7352        * @param {string} key Normalized key. (ie ngAttribute)
7353        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
7354        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
7355        *     Defaults to true.
7356        * @param {string=} attrName Optional none normalized name. Defaults to key.
7357        */
7358       $set: function(key, value, writeAttr, attrName) {
7359         // TODO: decide whether or not to throw an error if "class"
7360         //is set through this function since it may cause $updateClass to
7361         //become unstable.
7362
7363         var node = this.$$element[0],
7364             booleanKey = getBooleanAttrName(node, key),
7365             aliasedKey = getAliasedAttrName(key),
7366             observer = key,
7367             nodeName;
7368
7369         if (booleanKey) {
7370           this.$$element.prop(key, value);
7371           attrName = booleanKey;
7372         } else if (aliasedKey) {
7373           this[aliasedKey] = value;
7374           observer = aliasedKey;
7375         }
7376
7377         this[key] = value;
7378
7379         // translate normalized key to actual key
7380         if (attrName) {
7381           this.$attr[key] = attrName;
7382         } else {
7383           attrName = this.$attr[key];
7384           if (!attrName) {
7385             this.$attr[key] = attrName = snake_case(key, '-');
7386           }
7387         }
7388
7389         nodeName = nodeName_(this.$$element);
7390
7391         if ((nodeName === 'a' && key === 'href') ||
7392             (nodeName === 'img' && key === 'src')) {
7393           // sanitize a[href] and img[src] values
7394           this[key] = value = $$sanitizeUri(value, key === 'src');
7395         } else if (nodeName === 'img' && key === 'srcset') {
7396           // sanitize img[srcset] values
7397           var result = "";
7398
7399           // first check if there are spaces because it's not the same pattern
7400           var trimmedSrcset = trim(value);
7401           //                (   999x   ,|   999w   ,|   ,|,   )
7402           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
7403           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
7404
7405           // split srcset into tuple of uri and descriptor except for the last item
7406           var rawUris = trimmedSrcset.split(pattern);
7407
7408           // for each tuples
7409           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
7410           for (var i = 0; i < nbrUrisWith2parts; i++) {
7411             var innerIdx = i * 2;
7412             // sanitize the uri
7413             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
7414             // add the descriptor
7415             result += (" " + trim(rawUris[innerIdx + 1]));
7416           }
7417
7418           // split the last item into uri and descriptor
7419           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
7420
7421           // sanitize the last uri
7422           result += $$sanitizeUri(trim(lastTuple[0]), true);
7423
7424           // and add the last descriptor if any
7425           if (lastTuple.length === 2) {
7426             result += (" " + trim(lastTuple[1]));
7427           }
7428           this[key] = value = result;
7429         }
7430
7431         if (writeAttr !== false) {
7432           if (value === null || isUndefined(value)) {
7433             this.$$element.removeAttr(attrName);
7434           } else {
7435             this.$$element.attr(attrName, value);
7436           }
7437         }
7438
7439         // fire observers
7440         var $$observers = this.$$observers;
7441         $$observers && forEach($$observers[observer], function(fn) {
7442           try {
7443             fn(value);
7444           } catch (e) {
7445             $exceptionHandler(e);
7446           }
7447         });
7448       },
7449
7450
7451       /**
7452        * @ngdoc method
7453        * @name $compile.directive.Attributes#$observe
7454        * @kind function
7455        *
7456        * @description
7457        * Observes an interpolated attribute.
7458        *
7459        * The observer function will be invoked once during the next `$digest` following
7460        * compilation. The observer is then invoked whenever the interpolated value
7461        * changes.
7462        *
7463        * @param {string} key Normalized key. (ie ngAttribute) .
7464        * @param {function(interpolatedValue)} fn Function that will be called whenever
7465                 the interpolated value of the attribute changes.
7466        *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7467        * @returns {function()} Returns a deregistration function for this observer.
7468        */
7469       $observe: function(key, fn) {
7470         var attrs = this,
7471             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
7472             listeners = ($$observers[key] || ($$observers[key] = []));
7473
7474         listeners.push(fn);
7475         $rootScope.$evalAsync(function() {
7476           if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
7477             // no one registered attribute interpolation function, so lets call it manually
7478             fn(attrs[key]);
7479           }
7480         });
7481
7482         return function() {
7483           arrayRemove(listeners, fn);
7484         };
7485       }
7486     };
7487
7488
7489     function safeAddClass($element, className) {
7490       try {
7491         $element.addClass(className);
7492       } catch (e) {
7493         // ignore, since it means that we are trying to set class on
7494         // SVG element, where class name is read-only.
7495       }
7496     }
7497
7498
7499     var startSymbol = $interpolate.startSymbol(),
7500         endSymbol = $interpolate.endSymbol(),
7501         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
7502             ? identity
7503             : function denormalizeTemplate(template) {
7504               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7505         },
7506         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7507     var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
7508
7509     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7510       var bindings = $element.data('$binding') || [];
7511
7512       if (isArray(binding)) {
7513         bindings = bindings.concat(binding);
7514       } else {
7515         bindings.push(binding);
7516       }
7517
7518       $element.data('$binding', bindings);
7519     } : noop;
7520
7521     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
7522       safeAddClass($element, 'ng-binding');
7523     } : noop;
7524
7525     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
7526       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
7527       $element.data(dataName, scope);
7528     } : noop;
7529
7530     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
7531       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
7532     } : noop;
7533
7534     return compile;
7535
7536     //================================
7537
7538     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
7539                         previousCompileContext) {
7540       if (!($compileNodes instanceof jqLite)) {
7541         // jquery always rewraps, whereas we need to preserve the original selector so that we can
7542         // modify it.
7543         $compileNodes = jqLite($compileNodes);
7544       }
7545       // We can not compile top level text elements since text nodes can be merged and we will
7546       // not be able to attach scope data to them, so we will wrap them in <span>
7547       forEach($compileNodes, function(node, index) {
7548         if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7549           $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
7550         }
7551       });
7552       var compositeLinkFn =
7553               compileNodes($compileNodes, transcludeFn, $compileNodes,
7554                            maxPriority, ignoreDirective, previousCompileContext);
7555       compile.$$addScopeClass($compileNodes);
7556       var namespace = null;
7557       return function publicLinkFn(scope, cloneConnectFn, options) {
7558         assertArg(scope, 'scope');
7559
7560         if (previousCompileContext && previousCompileContext.needsNewScope) {
7561           // A parent directive did a replace and a directive on this element asked
7562           // for transclusion, which caused us to lose a layer of element on which
7563           // we could hold the new transclusion scope, so we will create it manually
7564           // here.
7565           scope = scope.$parent.$new();
7566         }
7567
7568         options = options || {};
7569         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7570           transcludeControllers = options.transcludeControllers,
7571           futureParentElement = options.futureParentElement;
7572
7573         // When `parentBoundTranscludeFn` is passed, it is a
7574         // `controllersBoundTransclude` function (it was previously passed
7575         // as `transclude` to directive.link) so we must unwrap it to get
7576         // its `boundTranscludeFn`
7577         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
7578           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
7579         }
7580
7581         if (!namespace) {
7582           namespace = detectNamespaceForChildElements(futureParentElement);
7583         }
7584         var $linkNode;
7585         if (namespace !== 'html') {
7586           // When using a directive with replace:true and templateUrl the $compileNodes
7587           // (or a child element inside of them)
7588           // might change, so we need to recreate the namespace adapted compileNodes
7589           // for call to the link function.
7590           // Note: This will already clone the nodes...
7591           $linkNode = jqLite(
7592             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7593           );
7594         } else if (cloneConnectFn) {
7595           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
7596           // and sometimes changes the structure of the DOM.
7597           $linkNode = JQLitePrototype.clone.call($compileNodes);
7598         } else {
7599           $linkNode = $compileNodes;
7600         }
7601
7602         if (transcludeControllers) {
7603           for (var controllerName in transcludeControllers) {
7604             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7605           }
7606         }
7607
7608         compile.$$addScopeInfo($linkNode, scope);
7609
7610         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7611         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7612         return $linkNode;
7613       };
7614     }
7615
7616     function detectNamespaceForChildElements(parentElement) {
7617       // TODO: Make this detect MathML as well...
7618       var node = parentElement && parentElement[0];
7619       if (!node) {
7620         return 'html';
7621       } else {
7622         return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7623       }
7624     }
7625
7626     /**
7627      * Compile function matches each node in nodeList against the directives. Once all directives
7628      * for a particular node are collected their compile functions are executed. The compile
7629      * functions return values - the linking functions - are combined into a composite linking
7630      * function, which is the a linking function for the node.
7631      *
7632      * @param {NodeList} nodeList an array of nodes or NodeList to compile
7633      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7634      *        scope argument is auto-generated to the new child of the transcluded parent scope.
7635      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7636      *        the rootElement must be set the jqLite collection of the compile root. This is
7637      *        needed so that the jqLite collection items can be replaced with widgets.
7638      * @param {number=} maxPriority Max directive priority.
7639      * @returns {Function} A composite linking function of all of the matched directives or null.
7640      */
7641     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7642                             previousCompileContext) {
7643       var linkFns = [],
7644           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7645
7646       for (var i = 0; i < nodeList.length; i++) {
7647         attrs = new Attributes();
7648
7649         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7650         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7651                                         ignoreDirective);
7652
7653         nodeLinkFn = (directives.length)
7654             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7655                                       null, [], [], previousCompileContext)
7656             : null;
7657
7658         if (nodeLinkFn && nodeLinkFn.scope) {
7659           compile.$$addScopeClass(attrs.$$element);
7660         }
7661
7662         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7663                       !(childNodes = nodeList[i].childNodes) ||
7664                       !childNodes.length)
7665             ? null
7666             : compileNodes(childNodes,
7667                  nodeLinkFn ? (
7668                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7669                      && nodeLinkFn.transclude) : transcludeFn);
7670
7671         if (nodeLinkFn || childLinkFn) {
7672           linkFns.push(i, nodeLinkFn, childLinkFn);
7673           linkFnFound = true;
7674           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7675         }
7676
7677         //use the previous context only for the first element in the virtual group
7678         previousCompileContext = null;
7679       }
7680
7681       // return a linking function if we have found anything, null otherwise
7682       return linkFnFound ? compositeLinkFn : null;
7683
7684       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7685         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7686         var stableNodeList;
7687
7688
7689         if (nodeLinkFnFound) {
7690           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7691           // offsets don't get screwed up
7692           var nodeListLength = nodeList.length;
7693           stableNodeList = new Array(nodeListLength);
7694
7695           // create a sparse array by only copying the elements which have a linkFn
7696           for (i = 0; i < linkFns.length; i+=3) {
7697             idx = linkFns[i];
7698             stableNodeList[idx] = nodeList[idx];
7699           }
7700         } else {
7701           stableNodeList = nodeList;
7702         }
7703
7704         for (i = 0, ii = linkFns.length; i < ii;) {
7705           node = stableNodeList[linkFns[i++]];
7706           nodeLinkFn = linkFns[i++];
7707           childLinkFn = linkFns[i++];
7708
7709           if (nodeLinkFn) {
7710             if (nodeLinkFn.scope) {
7711               childScope = scope.$new();
7712               compile.$$addScopeInfo(jqLite(node), childScope);
7713             } else {
7714               childScope = scope;
7715             }
7716
7717             if (nodeLinkFn.transcludeOnThisElement) {
7718               childBoundTranscludeFn = createBoundTranscludeFn(
7719                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
7720
7721             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7722               childBoundTranscludeFn = parentBoundTranscludeFn;
7723
7724             } else if (!parentBoundTranscludeFn && transcludeFn) {
7725               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7726
7727             } else {
7728               childBoundTranscludeFn = null;
7729             }
7730
7731             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7732
7733           } else if (childLinkFn) {
7734             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7735           }
7736         }
7737       }
7738     }
7739
7740     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
7741
7742       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7743
7744         if (!transcludedScope) {
7745           transcludedScope = scope.$new(false, containingScope);
7746           transcludedScope.$$transcluded = true;
7747         }
7748
7749         return transcludeFn(transcludedScope, cloneFn, {
7750           parentBoundTranscludeFn: previousBoundTranscludeFn,
7751           transcludeControllers: controllers,
7752           futureParentElement: futureParentElement
7753         });
7754       };
7755
7756       return boundTranscludeFn;
7757     }
7758
7759     /**
7760      * Looks for directives on the given node and adds them to the directive collection which is
7761      * sorted.
7762      *
7763      * @param node Node to search.
7764      * @param directives An array to which the directives are added to. This array is sorted before
7765      *        the function returns.
7766      * @param attrs The shared attrs object which is used to populate the normalized attributes.
7767      * @param {number=} maxPriority Max directive priority.
7768      */
7769     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7770       var nodeType = node.nodeType,
7771           attrsMap = attrs.$attr,
7772           match,
7773           className;
7774
7775       switch (nodeType) {
7776         case NODE_TYPE_ELEMENT: /* Element */
7777           // use the node name: <directive>
7778           addDirective(directives,
7779               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7780
7781           // iterate over the attributes
7782           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7783                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7784             var attrStartName = false;
7785             var attrEndName = false;
7786
7787             attr = nAttrs[j];
7788             name = attr.name;
7789             value = trim(attr.value);
7790
7791             // support ngAttr attribute binding
7792             ngAttrName = directiveNormalize(name);
7793             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7794               name = name.replace(PREFIX_REGEXP, '')
7795                 .substr(8).replace(/_(.)/g, function(match, letter) {
7796                   return letter.toUpperCase();
7797                 });
7798             }
7799
7800             var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
7801             if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
7802               attrStartName = name;
7803               attrEndName = name.substr(0, name.length - 5) + 'end';
7804               name = name.substr(0, name.length - 6);
7805             }
7806
7807             nName = directiveNormalize(name.toLowerCase());
7808             attrsMap[nName] = name;
7809             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7810                 attrs[nName] = value;
7811                 if (getBooleanAttrName(node, nName)) {
7812                   attrs[nName] = true; // presence means true
7813                 }
7814             }
7815             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7816             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7817                           attrEndName);
7818           }
7819
7820           // use class as directive
7821           className = node.className;
7822           if (isObject(className)) {
7823               // Maybe SVGAnimatedString
7824               className = className.animVal;
7825           }
7826           if (isString(className) && className !== '') {
7827             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7828               nName = directiveNormalize(match[2]);
7829               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7830                 attrs[nName] = trim(match[3]);
7831               }
7832               className = className.substr(match.index + match[0].length);
7833             }
7834           }
7835           break;
7836         case NODE_TYPE_TEXT: /* Text Node */
7837           if (msie === 11) {
7838             // Workaround for #11781
7839             while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
7840               node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
7841               node.parentNode.removeChild(node.nextSibling);
7842             }
7843           }
7844           addTextInterpolateDirective(directives, node.nodeValue);
7845           break;
7846         case NODE_TYPE_COMMENT: /* Comment */
7847           try {
7848             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7849             if (match) {
7850               nName = directiveNormalize(match[1]);
7851               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7852                 attrs[nName] = trim(match[2]);
7853               }
7854             }
7855           } catch (e) {
7856             // turns out that under some circumstances IE9 throws errors when one attempts to read
7857             // comment's node value.
7858             // Just ignore it and continue. (Can't seem to reproduce in test case.)
7859           }
7860           break;
7861       }
7862
7863       directives.sort(byPriority);
7864       return directives;
7865     }
7866
7867     /**
7868      * Given a node with an directive-start it collects all of the siblings until it finds
7869      * directive-end.
7870      * @param node
7871      * @param attrStart
7872      * @param attrEnd
7873      * @returns {*}
7874      */
7875     function groupScan(node, attrStart, attrEnd) {
7876       var nodes = [];
7877       var depth = 0;
7878       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7879         do {
7880           if (!node) {
7881             throw $compileMinErr('uterdir',
7882                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7883                       attrStart, attrEnd);
7884           }
7885           if (node.nodeType == NODE_TYPE_ELEMENT) {
7886             if (node.hasAttribute(attrStart)) depth++;
7887             if (node.hasAttribute(attrEnd)) depth--;
7888           }
7889           nodes.push(node);
7890           node = node.nextSibling;
7891         } while (depth > 0);
7892       } else {
7893         nodes.push(node);
7894       }
7895
7896       return jqLite(nodes);
7897     }
7898
7899     /**
7900      * Wrapper for linking function which converts normal linking function into a grouped
7901      * linking function.
7902      * @param linkFn
7903      * @param attrStart
7904      * @param attrEnd
7905      * @returns {Function}
7906      */
7907     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7908       return function(scope, element, attrs, controllers, transcludeFn) {
7909         element = groupScan(element[0], attrStart, attrEnd);
7910         return linkFn(scope, element, attrs, controllers, transcludeFn);
7911       };
7912     }
7913
7914     /**
7915      * Once the directives have been collected, their compile functions are executed. This method
7916      * is responsible for inlining directive templates as well as terminating the application
7917      * of the directives if the terminal directive has been reached.
7918      *
7919      * @param {Array} directives Array of collected directives to execute their compile function.
7920      *        this needs to be pre-sorted by priority order.
7921      * @param {Node} compileNode The raw DOM node to apply the compile functions to
7922      * @param {Object} templateAttrs The shared attribute function
7923      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7924      *                                                  scope argument is auto-generated to the new
7925      *                                                  child of the transcluded parent scope.
7926      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
7927      *                              argument has the root jqLite array so that we can replace nodes
7928      *                              on it.
7929      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
7930      *                                           compiling the transclusion.
7931      * @param {Array.<Function>} preLinkFns
7932      * @param {Array.<Function>} postLinkFns
7933      * @param {Object} previousCompileContext Context used for previous compilation of the current
7934      *                                        node
7935      * @returns {Function} linkFn
7936      */
7937     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
7938                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
7939                                    previousCompileContext) {
7940       previousCompileContext = previousCompileContext || {};
7941
7942       var terminalPriority = -Number.MAX_VALUE,
7943           newScopeDirective = previousCompileContext.newScopeDirective,
7944           controllerDirectives = previousCompileContext.controllerDirectives,
7945           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
7946           templateDirective = previousCompileContext.templateDirective,
7947           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
7948           hasTranscludeDirective = false,
7949           hasTemplate = false,
7950           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
7951           $compileNode = templateAttrs.$$element = jqLite(compileNode),
7952           directive,
7953           directiveName,
7954           $template,
7955           replaceDirective = originalReplaceDirective,
7956           childTranscludeFn = transcludeFn,
7957           linkFn,
7958           directiveValue;
7959
7960       // executes all directives on the current element
7961       for (var i = 0, ii = directives.length; i < ii; i++) {
7962         directive = directives[i];
7963         var attrStart = directive.$$start;
7964         var attrEnd = directive.$$end;
7965
7966         // collect multiblock sections
7967         if (attrStart) {
7968           $compileNode = groupScan(compileNode, attrStart, attrEnd);
7969         }
7970         $template = undefined;
7971
7972         if (terminalPriority > directive.priority) {
7973           break; // prevent further processing of directives
7974         }
7975
7976         if (directiveValue = directive.scope) {
7977
7978           // skip the check for directives with async templates, we'll check the derived sync
7979           // directive when the template arrives
7980           if (!directive.templateUrl) {
7981             if (isObject(directiveValue)) {
7982               // This directive is trying to add an isolated scope.
7983               // Check that there is no scope of any kind already
7984               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
7985                                 directive, $compileNode);
7986               newIsolateScopeDirective = directive;
7987             } else {
7988               // This directive is trying to add a child scope.
7989               // Check that there is no isolated scope already
7990               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
7991                                 $compileNode);
7992             }
7993           }
7994
7995           newScopeDirective = newScopeDirective || directive;
7996         }
7997
7998         directiveName = directive.name;
7999
8000         if (!directive.templateUrl && directive.controller) {
8001           directiveValue = directive.controller;
8002           controllerDirectives = controllerDirectives || createMap();
8003           assertNoDuplicate("'" + directiveName + "' controller",
8004               controllerDirectives[directiveName], directive, $compileNode);
8005           controllerDirectives[directiveName] = directive;
8006         }
8007
8008         if (directiveValue = directive.transclude) {
8009           hasTranscludeDirective = true;
8010
8011           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
8012           // This option should only be used by directives that know how to safely handle element transclusion,
8013           // where the transcluded nodes are added or replaced after linking.
8014           if (!directive.$$tlb) {
8015             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
8016             nonTlbTranscludeDirective = directive;
8017           }
8018
8019           if (directiveValue == 'element') {
8020             hasElementTranscludeDirective = true;
8021             terminalPriority = directive.priority;
8022             $template = $compileNode;
8023             $compileNode = templateAttrs.$$element =
8024                 jqLite(document.createComment(' ' + directiveName + ': ' +
8025                                               templateAttrs[directiveName] + ' '));
8026             compileNode = $compileNode[0];
8027             replaceWith(jqCollection, sliceArgs($template), compileNode);
8028
8029             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
8030                                         replaceDirective && replaceDirective.name, {
8031                                           // Don't pass in:
8032                                           // - controllerDirectives - otherwise we'll create duplicates controllers
8033                                           // - newIsolateScopeDirective or templateDirective - combining templates with
8034                                           //   element transclusion doesn't make sense.
8035                                           //
8036                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
8037                                           // on the same element more than once.
8038                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
8039                                         });
8040           } else {
8041             $template = jqLite(jqLiteClone(compileNode)).contents();
8042             $compileNode.empty(); // clear contents
8043             childTranscludeFn = compile($template, transcludeFn, undefined,
8044                 undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
8045           }
8046         }
8047
8048         if (directive.template) {
8049           hasTemplate = true;
8050           assertNoDuplicate('template', templateDirective, directive, $compileNode);
8051           templateDirective = directive;
8052
8053           directiveValue = (isFunction(directive.template))
8054               ? directive.template($compileNode, templateAttrs)
8055               : directive.template;
8056
8057           directiveValue = denormalizeTemplate(directiveValue);
8058
8059           if (directive.replace) {
8060             replaceDirective = directive;
8061             if (jqLiteIsTextNode(directiveValue)) {
8062               $template = [];
8063             } else {
8064               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
8065             }
8066             compileNode = $template[0];
8067
8068             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8069               throw $compileMinErr('tplrt',
8070                   "Template for directive '{0}' must have exactly one root element. {1}",
8071                   directiveName, '');
8072             }
8073
8074             replaceWith(jqCollection, $compileNode, compileNode);
8075
8076             var newTemplateAttrs = {$attr: {}};
8077
8078             // combine directives from the original node and from the template:
8079             // - take the array of directives for this element
8080             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
8081             // - collect directives from the template and sort them by priority
8082             // - combine directives as: processed + template + unprocessed
8083             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
8084             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
8085
8086             if (newIsolateScopeDirective || newScopeDirective) {
8087               // The original directive caused the current element to be replaced but this element
8088               // also needs to have a new scope, so we need to tell the template directives
8089               // that they would need to get their scope from further up, if they require transclusion
8090               markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
8091             }
8092             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
8093             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
8094
8095             ii = directives.length;
8096           } else {
8097             $compileNode.html(directiveValue);
8098           }
8099         }
8100
8101         if (directive.templateUrl) {
8102           hasTemplate = true;
8103           assertNoDuplicate('template', templateDirective, directive, $compileNode);
8104           templateDirective = directive;
8105
8106           if (directive.replace) {
8107             replaceDirective = directive;
8108           }
8109
8110           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8111               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8112                 controllerDirectives: controllerDirectives,
8113                 newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
8114                 newIsolateScopeDirective: newIsolateScopeDirective,
8115                 templateDirective: templateDirective,
8116                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
8117               });
8118           ii = directives.length;
8119         } else if (directive.compile) {
8120           try {
8121             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
8122             if (isFunction(linkFn)) {
8123               addLinkFns(null, linkFn, attrStart, attrEnd);
8124             } else if (linkFn) {
8125               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
8126             }
8127           } catch (e) {
8128             $exceptionHandler(e, startingTag($compileNode));
8129           }
8130         }
8131
8132         if (directive.terminal) {
8133           nodeLinkFn.terminal = true;
8134           terminalPriority = Math.max(terminalPriority, directive.priority);
8135         }
8136
8137       }
8138
8139       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
8140       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
8141       nodeLinkFn.templateOnThisElement = hasTemplate;
8142       nodeLinkFn.transclude = childTranscludeFn;
8143
8144       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
8145
8146       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
8147       return nodeLinkFn;
8148
8149       ////////////////////
8150
8151       function addLinkFns(pre, post, attrStart, attrEnd) {
8152         if (pre) {
8153           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
8154           pre.require = directive.require;
8155           pre.directiveName = directiveName;
8156           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8157             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
8158           }
8159           preLinkFns.push(pre);
8160         }
8161         if (post) {
8162           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
8163           post.require = directive.require;
8164           post.directiveName = directiveName;
8165           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8166             post = cloneAndAnnotateFn(post, {isolateScope: true});
8167           }
8168           postLinkFns.push(post);
8169         }
8170       }
8171
8172
8173       function getControllers(directiveName, require, $element, elementControllers) {
8174         var value;
8175
8176         if (isString(require)) {
8177           var match = require.match(REQUIRE_PREFIX_REGEXP);
8178           var name = require.substring(match[0].length);
8179           var inheritType = match[1] || match[3];
8180           var optional = match[2] === '?';
8181
8182           //If only parents then start at the parent element
8183           if (inheritType === '^^') {
8184             $element = $element.parent();
8185           //Otherwise attempt getting the controller from elementControllers in case
8186           //the element is transcluded (and has no data) and to avoid .data if possible
8187           } else {
8188             value = elementControllers && elementControllers[name];
8189             value = value && value.instance;
8190           }
8191
8192           if (!value) {
8193             var dataName = '$' + name + 'Controller';
8194             value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
8195           }
8196
8197           if (!value && !optional) {
8198             throw $compileMinErr('ctreq',
8199                 "Controller '{0}', required by directive '{1}', can't be found!",
8200                 name, directiveName);
8201           }
8202         } else if (isArray(require)) {
8203           value = [];
8204           for (var i = 0, ii = require.length; i < ii; i++) {
8205             value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8206           }
8207         }
8208
8209         return value || null;
8210       }
8211
8212       function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
8213         var elementControllers = createMap();
8214         for (var controllerKey in controllerDirectives) {
8215           var directive = controllerDirectives[controllerKey];
8216           var locals = {
8217             $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
8218             $element: $element,
8219             $attrs: attrs,
8220             $transclude: transcludeFn
8221           };
8222
8223           var controller = directive.controller;
8224           if (controller == '@') {
8225             controller = attrs[directive.name];
8226           }
8227
8228           var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8229
8230           // For directives with element transclusion the element is a comment,
8231           // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8232           // clean up (http://bugs.jquery.com/ticket/8335).
8233           // Instead, we save the controllers for the element in a local hash and attach to .data
8234           // later, once we have the actual element.
8235           elementControllers[directive.name] = controllerInstance;
8236           if (!hasElementTranscludeDirective) {
8237             $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8238           }
8239         }
8240         return elementControllers;
8241       }
8242
8243       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8244         var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8245             attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8246
8247         if (compileNode === linkNode) {
8248           attrs = templateAttrs;
8249           $element = templateAttrs.$$element;
8250         } else {
8251           $element = jqLite(linkNode);
8252           attrs = new Attributes($element, templateAttrs);
8253         }
8254
8255         controllerScope = scope;
8256         if (newIsolateScopeDirective) {
8257           isolateScope = scope.$new(true);
8258         } else if (newScopeDirective) {
8259           controllerScope = scope.$parent;
8260         }
8261
8262         if (boundTranscludeFn) {
8263           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
8264           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8265           transcludeFn = controllersBoundTransclude;
8266           transcludeFn.$$boundTransclude = boundTranscludeFn;
8267         }
8268
8269         if (controllerDirectives) {
8270           elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
8271         }
8272
8273         if (newIsolateScopeDirective) {
8274           // Initialize isolate scope bindings for new isolate scope directive.
8275           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
8276               templateDirective === newIsolateScopeDirective.$$originalDirective)));
8277           compile.$$addScopeClass($element, true);
8278           isolateScope.$$isolateBindings =
8279               newIsolateScopeDirective.$$isolateBindings;
8280           removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
8281                                         isolateScope.$$isolateBindings,
8282                                         newIsolateScopeDirective);
8283           if (removeScopeBindingWatches) {
8284             isolateScope.$on('$destroy', removeScopeBindingWatches);
8285           }
8286         }
8287
8288         // Initialize bindToController bindings
8289         for (var name in elementControllers) {
8290           var controllerDirective = controllerDirectives[name];
8291           var controller = elementControllers[name];
8292           var bindings = controllerDirective.$$bindings.bindToController;
8293
8294           if (controller.identifier && bindings) {
8295             removeControllerBindingWatches =
8296               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8297           }
8298
8299           var controllerResult = controller();
8300           if (controllerResult !== controller.instance) {
8301             // If the controller constructor has a return value, overwrite the instance
8302             // from setupControllers
8303             controller.instance = controllerResult;
8304             $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8305             removeControllerBindingWatches && removeControllerBindingWatches();
8306             removeControllerBindingWatches =
8307               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8308           }
8309         }
8310
8311         // PRELINKING
8312         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8313           linkFn = preLinkFns[i];
8314           invokeLinkFn(linkFn,
8315               linkFn.isolateScope ? isolateScope : scope,
8316               $element,
8317               attrs,
8318               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8319               transcludeFn
8320           );
8321         }
8322
8323         // RECURSION
8324         // We only pass the isolate scope, if the isolate directive has a template,
8325         // otherwise the child elements do not belong to the isolate directive.
8326         var scopeToChild = scope;
8327         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
8328           scopeToChild = isolateScope;
8329         }
8330         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
8331
8332         // POSTLINKING
8333         for (i = postLinkFns.length - 1; i >= 0; i--) {
8334           linkFn = postLinkFns[i];
8335           invokeLinkFn(linkFn,
8336               linkFn.isolateScope ? isolateScope : scope,
8337               $element,
8338               attrs,
8339               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8340               transcludeFn
8341           );
8342         }
8343
8344         // This is the function that is injected as `$transclude`.
8345         // Note: all arguments are optional!
8346         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8347           var transcludeControllers;
8348
8349           // No scope passed in:
8350           if (!isScope(scope)) {
8351             futureParentElement = cloneAttachFn;
8352             cloneAttachFn = scope;
8353             scope = undefined;
8354           }
8355
8356           if (hasElementTranscludeDirective) {
8357             transcludeControllers = elementControllers;
8358           }
8359           if (!futureParentElement) {
8360             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8361           }
8362           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
8363         }
8364       }
8365     }
8366
8367     // Depending upon the context in which a directive finds itself it might need to have a new isolated
8368     // or child scope created. For instance:
8369     // * if the directive has been pulled into a template because another directive with a higher priority
8370     // asked for element transclusion
8371     // * if the directive itself asks for transclusion but it is at the root of a template and the original
8372     // element was replaced. See https://github.com/angular/angular.js/issues/12936
8373     function markDirectiveScope(directives, isolateScope, newScope) {
8374       for (var j = 0, jj = directives.length; j < jj; j++) {
8375         directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
8376       }
8377     }
8378
8379     /**
8380      * looks up the directive and decorates it with exception handling and proper parameters. We
8381      * call this the boundDirective.
8382      *
8383      * @param {string} name name of the directive to look up.
8384      * @param {string} location The directive must be found in specific format.
8385      *   String containing any of theses characters:
8386      *
8387      *   * `E`: element name
8388      *   * `A': attribute
8389      *   * `C`: class
8390      *   * `M`: comment
8391      * @returns {boolean} true if directive was added.
8392      */
8393     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
8394                           endAttrName) {
8395       if (name === ignoreDirective) return null;
8396       var match = null;
8397       if (hasDirectives.hasOwnProperty(name)) {
8398         for (var directive, directives = $injector.get(name + Suffix),
8399             i = 0, ii = directives.length; i < ii; i++) {
8400           try {
8401             directive = directives[i];
8402             if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
8403                  directive.restrict.indexOf(location) != -1) {
8404               if (startAttrName) {
8405                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
8406               }
8407               tDirectives.push(directive);
8408               match = directive;
8409             }
8410           } catch (e) { $exceptionHandler(e); }
8411         }
8412       }
8413       return match;
8414     }
8415
8416
8417     /**
8418      * looks up the directive and returns true if it is a multi-element directive,
8419      * and therefore requires DOM nodes between -start and -end markers to be grouped
8420      * together.
8421      *
8422      * @param {string} name name of the directive to look up.
8423      * @returns true if directive was registered as multi-element.
8424      */
8425     function directiveIsMultiElement(name) {
8426       if (hasDirectives.hasOwnProperty(name)) {
8427         for (var directive, directives = $injector.get(name + Suffix),
8428             i = 0, ii = directives.length; i < ii; i++) {
8429           directive = directives[i];
8430           if (directive.multiElement) {
8431             return true;
8432           }
8433         }
8434       }
8435       return false;
8436     }
8437
8438     /**
8439      * When the element is replaced with HTML template then the new attributes
8440      * on the template need to be merged with the existing attributes in the DOM.
8441      * The desired effect is to have both of the attributes present.
8442      *
8443      * @param {object} dst destination attributes (original DOM)
8444      * @param {object} src source attributes (from the directive template)
8445      */
8446     function mergeTemplateAttributes(dst, src) {
8447       var srcAttr = src.$attr,
8448           dstAttr = dst.$attr,
8449           $element = dst.$$element;
8450
8451       // reapply the old attributes to the new element
8452       forEach(dst, function(value, key) {
8453         if (key.charAt(0) != '$') {
8454           if (src[key] && src[key] !== value) {
8455             value += (key === 'style' ? ';' : ' ') + src[key];
8456           }
8457           dst.$set(key, value, true, srcAttr[key]);
8458         }
8459       });
8460
8461       // copy the new attributes on the old attrs object
8462       forEach(src, function(value, key) {
8463         if (key == 'class') {
8464           safeAddClass($element, value);
8465           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
8466         } else if (key == 'style') {
8467           $element.attr('style', $element.attr('style') + ';' + value);
8468           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
8469           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
8470           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
8471           // have an attribute like "has-own-property" or "data-has-own-property", etc.
8472         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
8473           dst[key] = value;
8474           dstAttr[key] = srcAttr[key];
8475         }
8476       });
8477     }
8478
8479
8480     function compileTemplateUrl(directives, $compileNode, tAttrs,
8481         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
8482       var linkQueue = [],
8483           afterTemplateNodeLinkFn,
8484           afterTemplateChildLinkFn,
8485           beforeTemplateCompileNode = $compileNode[0],
8486           origAsyncDirective = directives.shift(),
8487           derivedSyncDirective = inherit(origAsyncDirective, {
8488             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
8489           }),
8490           templateUrl = (isFunction(origAsyncDirective.templateUrl))
8491               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
8492               : origAsyncDirective.templateUrl,
8493           templateNamespace = origAsyncDirective.templateNamespace;
8494
8495       $compileNode.empty();
8496
8497       $templateRequest(templateUrl)
8498         .then(function(content) {
8499           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
8500
8501           content = denormalizeTemplate(content);
8502
8503           if (origAsyncDirective.replace) {
8504             if (jqLiteIsTextNode(content)) {
8505               $template = [];
8506             } else {
8507               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
8508             }
8509             compileNode = $template[0];
8510
8511             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8512               throw $compileMinErr('tplrt',
8513                   "Template for directive '{0}' must have exactly one root element. {1}",
8514                   origAsyncDirective.name, templateUrl);
8515             }
8516
8517             tempTemplateAttrs = {$attr: {}};
8518             replaceWith($rootElement, $compileNode, compileNode);
8519             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8520
8521             if (isObject(origAsyncDirective.scope)) {
8522               // the original directive that caused the template to be loaded async required
8523               // an isolate scope
8524               markDirectiveScope(templateDirectives, true);
8525             }
8526             directives = templateDirectives.concat(directives);
8527             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
8528           } else {
8529             compileNode = beforeTemplateCompileNode;
8530             $compileNode.html(content);
8531           }
8532
8533           directives.unshift(derivedSyncDirective);
8534
8535           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
8536               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
8537               previousCompileContext);
8538           forEach($rootElement, function(node, i) {
8539             if (node == compileNode) {
8540               $rootElement[i] = $compileNode[0];
8541             }
8542           });
8543           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
8544
8545           while (linkQueue.length) {
8546             var scope = linkQueue.shift(),
8547                 beforeTemplateLinkNode = linkQueue.shift(),
8548                 linkRootElement = linkQueue.shift(),
8549                 boundTranscludeFn = linkQueue.shift(),
8550                 linkNode = $compileNode[0];
8551
8552             if (scope.$$destroyed) continue;
8553
8554             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8555               var oldClasses = beforeTemplateLinkNode.className;
8556
8557               if (!(previousCompileContext.hasElementTranscludeDirective &&
8558                   origAsyncDirective.replace)) {
8559                 // it was cloned therefore we have to clone as well.
8560                 linkNode = jqLiteClone(compileNode);
8561               }
8562               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8563
8564               // Copy in CSS classes from original node
8565               safeAddClass(jqLite(linkNode), oldClasses);
8566             }
8567             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8568               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8569             } else {
8570               childBoundTranscludeFn = boundTranscludeFn;
8571             }
8572             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8573               childBoundTranscludeFn);
8574           }
8575           linkQueue = null;
8576         });
8577
8578       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8579         var childBoundTranscludeFn = boundTranscludeFn;
8580         if (scope.$$destroyed) return;
8581         if (linkQueue) {
8582           linkQueue.push(scope,
8583                          node,
8584                          rootElement,
8585                          childBoundTranscludeFn);
8586         } else {
8587           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8588             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8589           }
8590           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8591         }
8592       };
8593     }
8594
8595
8596     /**
8597      * Sorting function for bound directives.
8598      */
8599     function byPriority(a, b) {
8600       var diff = b.priority - a.priority;
8601       if (diff !== 0) return diff;
8602       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8603       return a.index - b.index;
8604     }
8605
8606     function assertNoDuplicate(what, previousDirective, directive, element) {
8607
8608       function wrapModuleNameIfDefined(moduleName) {
8609         return moduleName ?
8610           (' (module: ' + moduleName + ')') :
8611           '';
8612       }
8613
8614       if (previousDirective) {
8615         throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
8616             previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
8617             directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
8618       }
8619     }
8620
8621
8622     function addTextInterpolateDirective(directives, text) {
8623       var interpolateFn = $interpolate(text, true);
8624       if (interpolateFn) {
8625         directives.push({
8626           priority: 0,
8627           compile: function textInterpolateCompileFn(templateNode) {
8628             var templateNodeParent = templateNode.parent(),
8629                 hasCompileParent = !!templateNodeParent.length;
8630
8631             // When transcluding a template that has bindings in the root
8632             // we don't have a parent and thus need to add the class during linking fn.
8633             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8634
8635             return function textInterpolateLinkFn(scope, node) {
8636               var parent = node.parent();
8637               if (!hasCompileParent) compile.$$addBindingClass(parent);
8638               compile.$$addBindingInfo(parent, interpolateFn.expressions);
8639               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8640                 node[0].nodeValue = value;
8641               });
8642             };
8643           }
8644         });
8645       }
8646     }
8647
8648
8649     function wrapTemplate(type, template) {
8650       type = lowercase(type || 'html');
8651       switch (type) {
8652       case 'svg':
8653       case 'math':
8654         var wrapper = document.createElement('div');
8655         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8656         return wrapper.childNodes[0].childNodes;
8657       default:
8658         return template;
8659       }
8660     }
8661
8662
8663     function getTrustedContext(node, attrNormalizedName) {
8664       if (attrNormalizedName == "srcdoc") {
8665         return $sce.HTML;
8666       }
8667       var tag = nodeName_(node);
8668       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8669       if (attrNormalizedName == "xlinkHref" ||
8670           (tag == "form" && attrNormalizedName == "action") ||
8671           (tag != "img" && (attrNormalizedName == "src" ||
8672                             attrNormalizedName == "ngSrc"))) {
8673         return $sce.RESOURCE_URL;
8674       }
8675     }
8676
8677
8678     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8679       var trustedContext = getTrustedContext(node, name);
8680       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8681
8682       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8683
8684       // no interpolation found -> ignore
8685       if (!interpolateFn) return;
8686
8687
8688       if (name === "multiple" && nodeName_(node) === "select") {
8689         throw $compileMinErr("selmulti",
8690             "Binding to the 'multiple' attribute is not supported. Element: {0}",
8691             startingTag(node));
8692       }
8693
8694       directives.push({
8695         priority: 100,
8696         compile: function() {
8697             return {
8698               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8699                 var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
8700
8701                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8702                   throw $compileMinErr('nodomevents',
8703                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8704                           "ng- versions (such as ng-click instead of onclick) instead.");
8705                 }
8706
8707                 // If the attribute has changed since last $interpolate()ed
8708                 var newValue = attr[name];
8709                 if (newValue !== value) {
8710                   // we need to interpolate again since the attribute value has been updated
8711                   // (e.g. by another directive's compile function)
8712                   // ensure unset/empty values make interpolateFn falsy
8713                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8714                   value = newValue;
8715                 }
8716
8717                 // if attribute was updated so that there is no interpolation going on we don't want to
8718                 // register any observers
8719                 if (!interpolateFn) return;
8720
8721                 // initialize attr object so that it's ready in case we need the value for isolate
8722                 // scope initialization, otherwise the value would not be available from isolate
8723                 // directive's linking fn during linking phase
8724                 attr[name] = interpolateFn(scope);
8725
8726                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8727                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
8728                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8729                     //special case for class attribute addition + removal
8730                     //so that class changes can tap into the animation
8731                     //hooks provided by the $animate service. Be sure to
8732                     //skip animations when the first digest occurs (when
8733                     //both the new and the old values are the same) since
8734                     //the CSS classes are the non-interpolated values
8735                     if (name === 'class' && newValue != oldValue) {
8736                       attr.$updateClass(newValue, oldValue);
8737                     } else {
8738                       attr.$set(name, newValue);
8739                     }
8740                   });
8741               }
8742             };
8743           }
8744       });
8745     }
8746
8747
8748     /**
8749      * This is a special jqLite.replaceWith, which can replace items which
8750      * have no parents, provided that the containing jqLite collection is provided.
8751      *
8752      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8753      *                               in the root of the tree.
8754      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8755      *                                  the shell, but replace its DOM node reference.
8756      * @param {Node} newNode The new DOM node.
8757      */
8758     function replaceWith($rootElement, elementsToRemove, newNode) {
8759       var firstElementToRemove = elementsToRemove[0],
8760           removeCount = elementsToRemove.length,
8761           parent = firstElementToRemove.parentNode,
8762           i, ii;
8763
8764       if ($rootElement) {
8765         for (i = 0, ii = $rootElement.length; i < ii; i++) {
8766           if ($rootElement[i] == firstElementToRemove) {
8767             $rootElement[i++] = newNode;
8768             for (var j = i, j2 = j + removeCount - 1,
8769                      jj = $rootElement.length;
8770                  j < jj; j++, j2++) {
8771               if (j2 < jj) {
8772                 $rootElement[j] = $rootElement[j2];
8773               } else {
8774                 delete $rootElement[j];
8775               }
8776             }
8777             $rootElement.length -= removeCount - 1;
8778
8779             // If the replaced element is also the jQuery .context then replace it
8780             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8781             // http://api.jquery.com/context/
8782             if ($rootElement.context === firstElementToRemove) {
8783               $rootElement.context = newNode;
8784             }
8785             break;
8786           }
8787         }
8788       }
8789
8790       if (parent) {
8791         parent.replaceChild(newNode, firstElementToRemove);
8792       }
8793
8794       // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8795       var fragment = document.createDocumentFragment();
8796       fragment.appendChild(firstElementToRemove);
8797
8798       if (jqLite.hasData(firstElementToRemove)) {
8799         // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8800         // data here because there's no public interface in jQuery to do that and copying over
8801         // event listeners (which is the main use of private data) wouldn't work anyway.
8802         jqLite.data(newNode, jqLite.data(firstElementToRemove));
8803
8804         // Remove data of the replaced element. We cannot just call .remove()
8805         // on the element it since that would deallocate scope that is needed
8806         // for the new node. Instead, remove the data "manually".
8807         if (!jQuery) {
8808           delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8809         } else {
8810           // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8811           // the replaced element. The cleanData version monkey-patched by Angular would cause
8812           // the scope to be trashed and we do need the very same scope to work with the new
8813           // element. However, we cannot just cache the non-patched version and use it here as
8814           // that would break if another library patches the method after Angular does (one
8815           // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8816           // skipped this one time.
8817           skipDestroyOnNextJQueryCleanData = true;
8818           jQuery.cleanData([firstElementToRemove]);
8819         }
8820       }
8821
8822       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8823         var element = elementsToRemove[k];
8824         jqLite(element).remove(); // must do this way to clean up expando
8825         fragment.appendChild(element);
8826         delete elementsToRemove[k];
8827       }
8828
8829       elementsToRemove[0] = newNode;
8830       elementsToRemove.length = 1;
8831     }
8832
8833
8834     function cloneAndAnnotateFn(fn, annotation) {
8835       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8836     }
8837
8838
8839     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8840       try {
8841         linkFn(scope, $element, attrs, controllers, transcludeFn);
8842       } catch (e) {
8843         $exceptionHandler(e, startingTag($element));
8844       }
8845     }
8846
8847
8848     // Set up $watches for isolate scope and controller bindings. This process
8849     // only occurs for isolate scopes and new scopes with controllerAs.
8850     function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
8851       var removeWatchCollection = [];
8852       forEach(bindings, function(definition, scopeName) {
8853         var attrName = definition.attrName,
8854         optional = definition.optional,
8855         mode = definition.mode, // @, =, or &
8856         lastValue,
8857         parentGet, parentSet, compare;
8858
8859         switch (mode) {
8860
8861           case '@':
8862             if (!optional && !hasOwnProperty.call(attrs, attrName)) {
8863               destination[scopeName] = attrs[attrName] = void 0;
8864             }
8865             attrs.$observe(attrName, function(value) {
8866               if (isString(value)) {
8867                 destination[scopeName] = value;
8868               }
8869             });
8870             attrs.$$observers[attrName].$$scope = scope;
8871             if (isString(attrs[attrName])) {
8872               // If the attribute has been provided then we trigger an interpolation to ensure
8873               // the value is there for use in the link fn
8874               destination[scopeName] = $interpolate(attrs[attrName])(scope);
8875             }
8876             break;
8877
8878           case '=':
8879             if (!hasOwnProperty.call(attrs, attrName)) {
8880               if (optional) break;
8881               attrs[attrName] = void 0;
8882             }
8883             if (optional && !attrs[attrName]) break;
8884
8885             parentGet = $parse(attrs[attrName]);
8886             if (parentGet.literal) {
8887               compare = equals;
8888             } else {
8889               compare = function(a, b) { return a === b || (a !== a && b !== b); };
8890             }
8891             parentSet = parentGet.assign || function() {
8892               // reset the change, or we will throw this exception on every $digest
8893               lastValue = destination[scopeName] = parentGet(scope);
8894               throw $compileMinErr('nonassign',
8895                   "Expression '{0}' used with directive '{1}' is non-assignable!",
8896                   attrs[attrName], directive.name);
8897             };
8898             lastValue = destination[scopeName] = parentGet(scope);
8899             var parentValueWatch = function parentValueWatch(parentValue) {
8900               if (!compare(parentValue, destination[scopeName])) {
8901                 // we are out of sync and need to copy
8902                 if (!compare(parentValue, lastValue)) {
8903                   // parent changed and it has precedence
8904                   destination[scopeName] = parentValue;
8905                 } else {
8906                   // if the parent can be assigned then do so
8907                   parentSet(scope, parentValue = destination[scopeName]);
8908                 }
8909               }
8910               return lastValue = parentValue;
8911             };
8912             parentValueWatch.$stateful = true;
8913             var removeWatch;
8914             if (definition.collection) {
8915               removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8916             } else {
8917               removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8918             }
8919             removeWatchCollection.push(removeWatch);
8920             break;
8921
8922           case '&':
8923             // Don't assign Object.prototype method to scope
8924             parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
8925
8926             // Don't assign noop to destination if expression is not valid
8927             if (parentGet === noop && optional) break;
8928
8929             destination[scopeName] = function(locals) {
8930               return parentGet(scope, locals);
8931             };
8932             break;
8933         }
8934       });
8935
8936       return removeWatchCollection.length && function removeWatches() {
8937         for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
8938           removeWatchCollection[i]();
8939         }
8940       };
8941     }
8942   }];
8943 }
8944
8945 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8946 /**
8947  * Converts all accepted directives format into proper directive name.
8948  * @param name Name to normalize
8949  */
8950 function directiveNormalize(name) {
8951   return camelCase(name.replace(PREFIX_REGEXP, ''));
8952 }
8953
8954 /**
8955  * @ngdoc type
8956  * @name $compile.directive.Attributes
8957  *
8958  * @description
8959  * A shared object between directive compile / linking functions which contains normalized DOM
8960  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
8961  * needed since all of these are treated as equivalent in Angular:
8962  *
8963  * ```
8964  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
8965  * ```
8966  */
8967
8968 /**
8969  * @ngdoc property
8970  * @name $compile.directive.Attributes#$attr
8971  *
8972  * @description
8973  * A map of DOM element attribute names to the normalized name. This is
8974  * needed to do reverse lookup from normalized name back to actual name.
8975  */
8976
8977
8978 /**
8979  * @ngdoc method
8980  * @name $compile.directive.Attributes#$set
8981  * @kind function
8982  *
8983  * @description
8984  * Set DOM element attribute value.
8985  *
8986  *
8987  * @param {string} name Normalized element attribute name of the property to modify. The name is
8988  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
8989  *          property to the original name.
8990  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
8991  */
8992
8993
8994
8995 /**
8996  * Closure compiler type information
8997  */
8998
8999 function nodesetLinkingFn(
9000   /* angular.Scope */ scope,
9001   /* NodeList */ nodeList,
9002   /* Element */ rootElement,
9003   /* function(Function) */ boundTranscludeFn
9004 ) {}
9005
9006 function directiveLinkingFn(
9007   /* nodesetLinkingFn */ nodesetLinkingFn,
9008   /* angular.Scope */ scope,
9009   /* Node */ node,
9010   /* Element */ rootElement,
9011   /* function(Function) */ boundTranscludeFn
9012 ) {}
9013
9014 function tokenDifference(str1, str2) {
9015   var values = '',
9016       tokens1 = str1.split(/\s+/),
9017       tokens2 = str2.split(/\s+/);
9018
9019   outer:
9020   for (var i = 0; i < tokens1.length; i++) {
9021     var token = tokens1[i];
9022     for (var j = 0; j < tokens2.length; j++) {
9023       if (token == tokens2[j]) continue outer;
9024     }
9025     values += (values.length > 0 ? ' ' : '') + token;
9026   }
9027   return values;
9028 }
9029
9030 function removeComments(jqNodes) {
9031   jqNodes = jqLite(jqNodes);
9032   var i = jqNodes.length;
9033
9034   if (i <= 1) {
9035     return jqNodes;
9036   }
9037
9038   while (i--) {
9039     var node = jqNodes[i];
9040     if (node.nodeType === NODE_TYPE_COMMENT) {
9041       splice.call(jqNodes, i, 1);
9042     }
9043   }
9044   return jqNodes;
9045 }
9046
9047 var $controllerMinErr = minErr('$controller');
9048
9049
9050 var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
9051 function identifierForController(controller, ident) {
9052   if (ident && isString(ident)) return ident;
9053   if (isString(controller)) {
9054     var match = CNTRL_REG.exec(controller);
9055     if (match) return match[3];
9056   }
9057 }
9058
9059
9060 /**
9061  * @ngdoc provider
9062  * @name $controllerProvider
9063  * @description
9064  * The {@link ng.$controller $controller service} is used by Angular to create new
9065  * controllers.
9066  *
9067  * This provider allows controller registration via the
9068  * {@link ng.$controllerProvider#register register} method.
9069  */
9070 function $ControllerProvider() {
9071   var controllers = {},
9072       globals = false;
9073
9074   /**
9075    * @ngdoc method
9076    * @name $controllerProvider#register
9077    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
9078    *    the names and the values are the constructors.
9079    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
9080    *    annotations in the array notation).
9081    */
9082   this.register = function(name, constructor) {
9083     assertNotHasOwnProperty(name, 'controller');
9084     if (isObject(name)) {
9085       extend(controllers, name);
9086     } else {
9087       controllers[name] = constructor;
9088     }
9089   };
9090
9091   /**
9092    * @ngdoc method
9093    * @name $controllerProvider#allowGlobals
9094    * @description If called, allows `$controller` to find controller constructors on `window`
9095    */
9096   this.allowGlobals = function() {
9097     globals = true;
9098   };
9099
9100
9101   this.$get = ['$injector', '$window', function($injector, $window) {
9102
9103     /**
9104      * @ngdoc service
9105      * @name $controller
9106      * @requires $injector
9107      *
9108      * @param {Function|string} constructor If called with a function then it's considered to be the
9109      *    controller constructor function. Otherwise it's considered to be a string which is used
9110      *    to retrieve the controller constructor using the following steps:
9111      *
9112      *    * check if a controller with given name is registered via `$controllerProvider`
9113      *    * check if evaluating the string on the current scope returns a constructor
9114      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
9115      *      `window` object (not recommended)
9116      *
9117      *    The string can use the `controller as property` syntax, where the controller instance is published
9118      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
9119      *    to work correctly.
9120      *
9121      * @param {Object} locals Injection locals for Controller.
9122      * @return {Object} Instance of given controller.
9123      *
9124      * @description
9125      * `$controller` service is responsible for instantiating controllers.
9126      *
9127      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
9128      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
9129      */
9130     return function(expression, locals, later, ident) {
9131       // PRIVATE API:
9132       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
9133       //                     If true, $controller will allocate the object with the correct
9134       //                     prototype chain, but will not invoke the controller until a returned
9135       //                     callback is invoked.
9136       //   param `ident` --- An optional label which overrides the label parsed from the controller
9137       //                     expression, if any.
9138       var instance, match, constructor, identifier;
9139       later = later === true;
9140       if (ident && isString(ident)) {
9141         identifier = ident;
9142       }
9143
9144       if (isString(expression)) {
9145         match = expression.match(CNTRL_REG);
9146         if (!match) {
9147           throw $controllerMinErr('ctrlfmt',
9148             "Badly formed controller string '{0}'. " +
9149             "Must match `__name__ as __id__` or `__name__`.", expression);
9150         }
9151         constructor = match[1],
9152         identifier = identifier || match[3];
9153         expression = controllers.hasOwnProperty(constructor)
9154             ? controllers[constructor]
9155             : getter(locals.$scope, constructor, true) ||
9156                 (globals ? getter($window, constructor, true) : undefined);
9157
9158         assertArgFn(expression, constructor, true);
9159       }
9160
9161       if (later) {
9162         // Instantiate controller later:
9163         // This machinery is used to create an instance of the object before calling the
9164         // controller's constructor itself.
9165         //
9166         // This allows properties to be added to the controller before the constructor is
9167         // invoked. Primarily, this is used for isolate scope bindings in $compile.
9168         //
9169         // This feature is not intended for use by applications, and is thus not documented
9170         // publicly.
9171         // Object creation: http://jsperf.com/create-constructor/2
9172         var controllerPrototype = (isArray(expression) ?
9173           expression[expression.length - 1] : expression).prototype;
9174         instance = Object.create(controllerPrototype || null);
9175
9176         if (identifier) {
9177           addIdentifier(locals, identifier, instance, constructor || expression.name);
9178         }
9179
9180         var instantiate;
9181         return instantiate = extend(function() {
9182           var result = $injector.invoke(expression, instance, locals, constructor);
9183           if (result !== instance && (isObject(result) || isFunction(result))) {
9184             instance = result;
9185             if (identifier) {
9186               // If result changed, re-assign controllerAs value to scope.
9187               addIdentifier(locals, identifier, instance, constructor || expression.name);
9188             }
9189           }
9190           return instance;
9191         }, {
9192           instance: instance,
9193           identifier: identifier
9194         });
9195       }
9196
9197       instance = $injector.instantiate(expression, locals, constructor);
9198
9199       if (identifier) {
9200         addIdentifier(locals, identifier, instance, constructor || expression.name);
9201       }
9202
9203       return instance;
9204     };
9205
9206     function addIdentifier(locals, identifier, instance, name) {
9207       if (!(locals && isObject(locals.$scope))) {
9208         throw minErr('$controller')('noscp',
9209           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
9210           name, identifier);
9211       }
9212
9213       locals.$scope[identifier] = instance;
9214     }
9215   }];
9216 }
9217
9218 /**
9219  * @ngdoc service
9220  * @name $document
9221  * @requires $window
9222  *
9223  * @description
9224  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
9225  *
9226  * @example
9227    <example module="documentExample">
9228      <file name="index.html">
9229        <div ng-controller="ExampleController">
9230          <p>$document title: <b ng-bind="title"></b></p>
9231          <p>window.document title: <b ng-bind="windowTitle"></b></p>
9232        </div>
9233      </file>
9234      <file name="script.js">
9235        angular.module('documentExample', [])
9236          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
9237            $scope.title = $document[0].title;
9238            $scope.windowTitle = angular.element(window.document)[0].title;
9239          }]);
9240      </file>
9241    </example>
9242  */
9243 function $DocumentProvider() {
9244   this.$get = ['$window', function(window) {
9245     return jqLite(window.document);
9246   }];
9247 }
9248
9249 /**
9250  * @ngdoc service
9251  * @name $exceptionHandler
9252  * @requires ng.$log
9253  *
9254  * @description
9255  * Any uncaught exception in angular expressions is delegated to this service.
9256  * The default implementation simply delegates to `$log.error` which logs it into
9257  * the browser console.
9258  *
9259  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
9260  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
9261  *
9262  * ## Example:
9263  *
9264  * ```js
9265  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
9266  *     return function(exception, cause) {
9267  *       exception.message += ' (caused by "' + cause + '")';
9268  *       throw exception;
9269  *     };
9270  *   });
9271  * ```
9272  *
9273  * This example will override the normal action of `$exceptionHandler`, to make angular
9274  * exceptions fail hard when they happen, instead of just logging to the console.
9275  *
9276  * <hr />
9277  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
9278  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
9279  * (unless executed during a digest).
9280  *
9281  * If you wish, you can manually delegate exceptions, e.g.
9282  * `try { ... } catch(e) { $exceptionHandler(e); }`
9283  *
9284  * @param {Error} exception Exception associated with the error.
9285  * @param {string=} cause optional information about the context in which
9286  *       the error was thrown.
9287  *
9288  */
9289 function $ExceptionHandlerProvider() {
9290   this.$get = ['$log', function($log) {
9291     return function(exception, cause) {
9292       $log.error.apply($log, arguments);
9293     };
9294   }];
9295 }
9296
9297 var $$ForceReflowProvider = function() {
9298   this.$get = ['$document', function($document) {
9299     return function(domNode) {
9300       //the line below will force the browser to perform a repaint so
9301       //that all the animated elements within the animation frame will
9302       //be properly updated and drawn on screen. This is required to
9303       //ensure that the preparation animation is properly flushed so that
9304       //the active state picks up from there. DO NOT REMOVE THIS LINE.
9305       //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
9306       //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
9307       //WILL TAKE YEARS AWAY FROM YOUR LIFE.
9308       if (domNode) {
9309         if (!domNode.nodeType && domNode instanceof jqLite) {
9310           domNode = domNode[0];
9311         }
9312       } else {
9313         domNode = $document[0].body;
9314       }
9315       return domNode.offsetWidth + 1;
9316     };
9317   }];
9318 };
9319
9320 var APPLICATION_JSON = 'application/json';
9321 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
9322 var JSON_START = /^\[|^\{(?!\{)/;
9323 var JSON_ENDS = {
9324   '[': /]$/,
9325   '{': /}$/
9326 };
9327 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
9328 var $httpMinErr = minErr('$http');
9329 var $httpMinErrLegacyFn = function(method) {
9330   return function() {
9331     throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
9332   };
9333 };
9334
9335 function serializeValue(v) {
9336   if (isObject(v)) {
9337     return isDate(v) ? v.toISOString() : toJson(v);
9338   }
9339   return v;
9340 }
9341
9342
9343 function $HttpParamSerializerProvider() {
9344   /**
9345    * @ngdoc service
9346    * @name $httpParamSerializer
9347    * @description
9348    *
9349    * Default {@link $http `$http`} params serializer that converts objects to strings
9350    * according to the following rules:
9351    *
9352    * * `{'foo': 'bar'}` results in `foo=bar`
9353    * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
9354    * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
9355    * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
9356    *
9357    * Note that serializer will sort the request parameters alphabetically.
9358    * */
9359
9360   this.$get = function() {
9361     return function ngParamSerializer(params) {
9362       if (!params) return '';
9363       var parts = [];
9364       forEachSorted(params, function(value, key) {
9365         if (value === null || isUndefined(value)) return;
9366         if (isArray(value)) {
9367           forEach(value, function(v, k) {
9368             parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
9369           });
9370         } else {
9371           parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
9372         }
9373       });
9374
9375       return parts.join('&');
9376     };
9377   };
9378 }
9379
9380 function $HttpParamSerializerJQLikeProvider() {
9381   /**
9382    * @ngdoc service
9383    * @name $httpParamSerializerJQLike
9384    * @description
9385    *
9386    * Alternative {@link $http `$http`} params serializer that follows
9387    * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
9388    * The serializer will also sort the params alphabetically.
9389    *
9390    * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
9391    *
9392    * ```js
9393    * $http({
9394    *   url: myUrl,
9395    *   method: 'GET',
9396    *   params: myParams,
9397    *   paramSerializer: '$httpParamSerializerJQLike'
9398    * });
9399    * ```
9400    *
9401    * It is also possible to set it as the default `paramSerializer` in the
9402    * {@link $httpProvider#defaults `$httpProvider`}.
9403    *
9404    * Additionally, you can inject the serializer and use it explicitly, for example to serialize
9405    * form data for submission:
9406    *
9407    * ```js
9408    * .controller(function($http, $httpParamSerializerJQLike) {
9409    *   //...
9410    *
9411    *   $http({
9412    *     url: myUrl,
9413    *     method: 'POST',
9414    *     data: $httpParamSerializerJQLike(myData),
9415    *     headers: {
9416    *       'Content-Type': 'application/x-www-form-urlencoded'
9417    *     }
9418    *   });
9419    *
9420    * });
9421    * ```
9422    *
9423    * */
9424   this.$get = function() {
9425     return function jQueryLikeParamSerializer(params) {
9426       if (!params) return '';
9427       var parts = [];
9428       serialize(params, '', true);
9429       return parts.join('&');
9430
9431       function serialize(toSerialize, prefix, topLevel) {
9432         if (toSerialize === null || isUndefined(toSerialize)) return;
9433         if (isArray(toSerialize)) {
9434           forEach(toSerialize, function(value, index) {
9435             serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
9436           });
9437         } else if (isObject(toSerialize) && !isDate(toSerialize)) {
9438           forEachSorted(toSerialize, function(value, key) {
9439             serialize(value, prefix +
9440                 (topLevel ? '' : '[') +
9441                 key +
9442                 (topLevel ? '' : ']'));
9443           });
9444         } else {
9445           parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
9446         }
9447       }
9448     };
9449   };
9450 }
9451
9452 function defaultHttpResponseTransform(data, headers) {
9453   if (isString(data)) {
9454     // Strip json vulnerability protection prefix and trim whitespace
9455     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
9456
9457     if (tempData) {
9458       var contentType = headers('Content-Type');
9459       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
9460         data = fromJson(tempData);
9461       }
9462     }
9463   }
9464
9465   return data;
9466 }
9467
9468 function isJsonLike(str) {
9469     var jsonStart = str.match(JSON_START);
9470     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
9471 }
9472
9473 /**
9474  * Parse headers into key value object
9475  *
9476  * @param {string} headers Raw headers as a string
9477  * @returns {Object} Parsed headers as key value object
9478  */
9479 function parseHeaders(headers) {
9480   var parsed = createMap(), i;
9481
9482   function fillInParsed(key, val) {
9483     if (key) {
9484       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
9485     }
9486   }
9487
9488   if (isString(headers)) {
9489     forEach(headers.split('\n'), function(line) {
9490       i = line.indexOf(':');
9491       fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
9492     });
9493   } else if (isObject(headers)) {
9494     forEach(headers, function(headerVal, headerKey) {
9495       fillInParsed(lowercase(headerKey), trim(headerVal));
9496     });
9497   }
9498
9499   return parsed;
9500 }
9501
9502
9503 /**
9504  * Returns a function that provides access to parsed headers.
9505  *
9506  * Headers are lazy parsed when first requested.
9507  * @see parseHeaders
9508  *
9509  * @param {(string|Object)} headers Headers to provide access to.
9510  * @returns {function(string=)} Returns a getter function which if called with:
9511  *
9512  *   - if called with single an argument returns a single header value or null
9513  *   - if called with no arguments returns an object containing all headers.
9514  */
9515 function headersGetter(headers) {
9516   var headersObj;
9517
9518   return function(name) {
9519     if (!headersObj) headersObj =  parseHeaders(headers);
9520
9521     if (name) {
9522       var value = headersObj[lowercase(name)];
9523       if (value === void 0) {
9524         value = null;
9525       }
9526       return value;
9527     }
9528
9529     return headersObj;
9530   };
9531 }
9532
9533
9534 /**
9535  * Chain all given functions
9536  *
9537  * This function is used for both request and response transforming
9538  *
9539  * @param {*} data Data to transform.
9540  * @param {function(string=)} headers HTTP headers getter fn.
9541  * @param {number} status HTTP status code of the response.
9542  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
9543  * @returns {*} Transformed data.
9544  */
9545 function transformData(data, headers, status, fns) {
9546   if (isFunction(fns)) {
9547     return fns(data, headers, status);
9548   }
9549
9550   forEach(fns, function(fn) {
9551     data = fn(data, headers, status);
9552   });
9553
9554   return data;
9555 }
9556
9557
9558 function isSuccess(status) {
9559   return 200 <= status && status < 300;
9560 }
9561
9562
9563 /**
9564  * @ngdoc provider
9565  * @name $httpProvider
9566  * @description
9567  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
9568  * */
9569 function $HttpProvider() {
9570   /**
9571    * @ngdoc property
9572    * @name $httpProvider#defaults
9573    * @description
9574    *
9575    * Object containing default values for all {@link ng.$http $http} requests.
9576    *
9577    * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
9578    * that will provide the cache for all requests who set their `cache` property to `true`.
9579    * If you set the `defaults.cache = false` then only requests that specify their own custom
9580    * cache object will be cached. See {@link $http#caching $http Caching} for more information.
9581    *
9582    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
9583    * Defaults value is `'XSRF-TOKEN'`.
9584    *
9585    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
9586    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
9587    *
9588    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
9589    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
9590    * setting default headers.
9591    *     - **`defaults.headers.common`**
9592    *     - **`defaults.headers.post`**
9593    *     - **`defaults.headers.put`**
9594    *     - **`defaults.headers.patch`**
9595    *
9596    *
9597    * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
9598    *  used to the prepare string representation of request parameters (specified as an object).
9599    *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
9600    *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
9601    *
9602    **/
9603   var defaults = this.defaults = {
9604     // transform incoming response data
9605     transformResponse: [defaultHttpResponseTransform],
9606
9607     // transform outgoing request data
9608     transformRequest: [function(d) {
9609       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
9610     }],
9611
9612     // default headers
9613     headers: {
9614       common: {
9615         'Accept': 'application/json, text/plain, */*'
9616       },
9617       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9618       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9619       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
9620     },
9621
9622     xsrfCookieName: 'XSRF-TOKEN',
9623     xsrfHeaderName: 'X-XSRF-TOKEN',
9624
9625     paramSerializer: '$httpParamSerializer'
9626   };
9627
9628   var useApplyAsync = false;
9629   /**
9630    * @ngdoc method
9631    * @name $httpProvider#useApplyAsync
9632    * @description
9633    *
9634    * Configure $http service to combine processing of multiple http responses received at around
9635    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
9636    * significant performance improvement for bigger applications that make many HTTP requests
9637    * concurrently (common during application bootstrap).
9638    *
9639    * Defaults to false. If no value is specified, returns the current configured value.
9640    *
9641    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
9642    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
9643    *    to load and share the same digest cycle.
9644    *
9645    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9646    *    otherwise, returns the current configured value.
9647    **/
9648   this.useApplyAsync = function(value) {
9649     if (isDefined(value)) {
9650       useApplyAsync = !!value;
9651       return this;
9652     }
9653     return useApplyAsync;
9654   };
9655
9656   var useLegacyPromise = true;
9657   /**
9658    * @ngdoc method
9659    * @name $httpProvider#useLegacyPromiseExtensions
9660    * @description
9661    *
9662    * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
9663    * This should be used to make sure that applications work without these methods.
9664    *
9665    * Defaults to true. If no value is specified, returns the current configured value.
9666    *
9667    * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
9668    *
9669    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9670    *    otherwise, returns the current configured value.
9671    **/
9672   this.useLegacyPromiseExtensions = function(value) {
9673     if (isDefined(value)) {
9674       useLegacyPromise = !!value;
9675       return this;
9676     }
9677     return useLegacyPromise;
9678   };
9679
9680   /**
9681    * @ngdoc property
9682    * @name $httpProvider#interceptors
9683    * @description
9684    *
9685    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
9686    * pre-processing of request or postprocessing of responses.
9687    *
9688    * These service factories are ordered by request, i.e. they are applied in the same order as the
9689    * array, on request, but reverse order, on response.
9690    *
9691    * {@link ng.$http#interceptors Interceptors detailed info}
9692    **/
9693   var interceptorFactories = this.interceptors = [];
9694
9695   this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
9696       function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
9697
9698     var defaultCache = $cacheFactory('$http');
9699
9700     /**
9701      * Make sure that default param serializer is exposed as a function
9702      */
9703     defaults.paramSerializer = isString(defaults.paramSerializer) ?
9704       $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
9705
9706     /**
9707      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
9708      * The reversal is needed so that we can build up the interception chain around the
9709      * server request.
9710      */
9711     var reversedInterceptors = [];
9712
9713     forEach(interceptorFactories, function(interceptorFactory) {
9714       reversedInterceptors.unshift(isString(interceptorFactory)
9715           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
9716     });
9717
9718     /**
9719      * @ngdoc service
9720      * @kind function
9721      * @name $http
9722      * @requires ng.$httpBackend
9723      * @requires $cacheFactory
9724      * @requires $rootScope
9725      * @requires $q
9726      * @requires $injector
9727      *
9728      * @description
9729      * The `$http` service is a core Angular service that facilitates communication with the remote
9730      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
9731      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
9732      *
9733      * For unit testing applications that use `$http` service, see
9734      * {@link ngMock.$httpBackend $httpBackend mock}.
9735      *
9736      * For a higher level of abstraction, please check out the {@link ngResource.$resource
9737      * $resource} service.
9738      *
9739      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
9740      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
9741      * it is important to familiarize yourself with these APIs and the guarantees they provide.
9742      *
9743      *
9744      * ## General usage
9745      * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
9746      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
9747      *
9748      * ```js
9749      *   // Simple GET request example:
9750      *   $http({
9751      *     method: 'GET',
9752      *     url: '/someUrl'
9753      *   }).then(function successCallback(response) {
9754      *       // this callback will be called asynchronously
9755      *       // when the response is available
9756      *     }, function errorCallback(response) {
9757      *       // called asynchronously if an error occurs
9758      *       // or server returns response with an error status.
9759      *     });
9760      * ```
9761      *
9762      * The response object has these properties:
9763      *
9764      *   - **data** – `{string|Object}` – The response body transformed with the transform
9765      *     functions.
9766      *   - **status** – `{number}` – HTTP status code of the response.
9767      *   - **headers** – `{function([headerName])}` – Header getter function.
9768      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9769      *   - **statusText** – `{string}` – HTTP status text of the response.
9770      *
9771      * A response status code between 200 and 299 is considered a success status and
9772      * will result in the success callback being called. Note that if the response is a redirect,
9773      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
9774      * called for such responses.
9775      *
9776      *
9777      * ## Shortcut methods
9778      *
9779      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
9780      * request data must be passed in for POST/PUT requests. An optional config can be passed as the
9781      * last argument.
9782      *
9783      * ```js
9784      *   $http.get('/someUrl', config).then(successCallback, errorCallback);
9785      *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
9786      * ```
9787      *
9788      * Complete list of shortcut methods:
9789      *
9790      * - {@link ng.$http#get $http.get}
9791      * - {@link ng.$http#head $http.head}
9792      * - {@link ng.$http#post $http.post}
9793      * - {@link ng.$http#put $http.put}
9794      * - {@link ng.$http#delete $http.delete}
9795      * - {@link ng.$http#jsonp $http.jsonp}
9796      * - {@link ng.$http#patch $http.patch}
9797      *
9798      *
9799      * ## Writing Unit Tests that use $http
9800      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
9801      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
9802      * request using trained responses.
9803      *
9804      * ```
9805      * $httpBackend.expectGET(...);
9806      * $http.get(...);
9807      * $httpBackend.flush();
9808      * ```
9809      *
9810      * ## Deprecation Notice
9811      * <div class="alert alert-danger">
9812      *   The `$http` legacy promise methods `success` and `error` have been deprecated.
9813      *   Use the standard `then` method instead.
9814      *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
9815      *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
9816      * </div>
9817      *
9818      * ## Setting HTTP Headers
9819      *
9820      * The $http service will automatically add certain HTTP headers to all requests. These defaults
9821      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
9822      * object, which currently contains this default configuration:
9823      *
9824      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
9825      *   - `Accept: application/json, text/plain, * / *`
9826      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
9827      *   - `Content-Type: application/json`
9828      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
9829      *   - `Content-Type: application/json`
9830      *
9831      * To add or overwrite these defaults, simply add or remove a property from these configuration
9832      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
9833      * with the lowercased HTTP method name as the key, e.g.
9834      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
9835      *
9836      * The defaults can also be set at runtime via the `$http.defaults` object in the same
9837      * fashion. For example:
9838      *
9839      * ```
9840      * module.run(function($http) {
9841      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
9842      * });
9843      * ```
9844      *
9845      * In addition, you can supply a `headers` property in the config object passed when
9846      * calling `$http(config)`, which overrides the defaults without changing them globally.
9847      *
9848      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
9849      * Use the `headers` property, setting the desired header to `undefined`. For example:
9850      *
9851      * ```js
9852      * var req = {
9853      *  method: 'POST',
9854      *  url: 'http://example.com',
9855      *  headers: {
9856      *    'Content-Type': undefined
9857      *  },
9858      *  data: { test: 'test' }
9859      * }
9860      *
9861      * $http(req).then(function(){...}, function(){...});
9862      * ```
9863      *
9864      * ## Transforming Requests and Responses
9865      *
9866      * Both requests and responses can be transformed using transformation functions: `transformRequest`
9867      * and `transformResponse`. These properties can be a single function that returns
9868      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9869      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9870      *
9871      * ### Default Transformations
9872      *
9873      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9874      * `defaults.transformResponse` properties. If a request does not provide its own transformations
9875      * then these will be applied.
9876      *
9877      * You can augment or replace the default transformations by modifying these properties by adding to or
9878      * replacing the array.
9879      *
9880      * Angular provides the following default transformations:
9881      *
9882      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9883      *
9884      * - If the `data` property of the request configuration object contains an object, serialize it
9885      *   into JSON format.
9886      *
9887      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9888      *
9889      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9890      *  - If JSON response is detected, deserialize it using a JSON parser.
9891      *
9892      *
9893      * ### Overriding the Default Transformations Per Request
9894      *
9895      * If you wish override the request/response transformations only for a single request then provide
9896      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9897      * into `$http`.
9898      *
9899      * Note that if you provide these properties on the config object the default transformations will be
9900      * overwritten. If you wish to augment the default transformations then you must include them in your
9901      * local transformation array.
9902      *
9903      * The following code demonstrates adding a new response transformation to be run after the default response
9904      * transformations have been run.
9905      *
9906      * ```js
9907      * function appendTransform(defaults, transform) {
9908      *
9909      *   // We can't guarantee that the default transformation is an array
9910      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9911      *
9912      *   // Append the new transformation to the defaults
9913      *   return defaults.concat(transform);
9914      * }
9915      *
9916      * $http({
9917      *   url: '...',
9918      *   method: 'GET',
9919      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9920      *     return doTransform(value);
9921      *   })
9922      * });
9923      * ```
9924      *
9925      *
9926      * ## Caching
9927      *
9928      * To enable caching, set the request configuration `cache` property to `true` (to use default
9929      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
9930      * When the cache is enabled, `$http` stores the response from the server in the specified
9931      * cache. The next time the same request is made, the response is served from the cache without
9932      * sending a request to the server.
9933      *
9934      * Note that even if the response is served from cache, delivery of the data is asynchronous in
9935      * the same way that real requests are.
9936      *
9937      * If there are multiple GET requests for the same URL that should be cached using the same
9938      * cache, but the cache is not populated yet, only one request to the server will be made and
9939      * the remaining requests will be fulfilled using the response from the first request.
9940      *
9941      * You can change the default cache to a new object (built with
9942      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
9943      * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
9944      * their `cache` property to `true` will now use this cache object.
9945      *
9946      * If you set the default cache to `false` then only requests that specify their own custom
9947      * cache object will be cached.
9948      *
9949      * ## Interceptors
9950      *
9951      * Before you start creating interceptors, be sure to understand the
9952      * {@link ng.$q $q and deferred/promise APIs}.
9953      *
9954      * For purposes of global error handling, authentication, or any kind of synchronous or
9955      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
9956      * able to intercept requests before they are handed to the server and
9957      * responses before they are handed over to the application code that
9958      * initiated these requests. The interceptors leverage the {@link ng.$q
9959      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
9960      *
9961      * The interceptors are service factories that are registered with the `$httpProvider` by
9962      * adding them to the `$httpProvider.interceptors` array. The factory is called and
9963      * injected with dependencies (if specified) and returns the interceptor.
9964      *
9965      * There are two kinds of interceptors (and two kinds of rejection interceptors):
9966      *
9967      *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
9968      *     modify the `config` object or create a new one. The function needs to return the `config`
9969      *     object directly, or a promise containing the `config` or a new `config` object.
9970      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
9971      *     resolved with a rejection.
9972      *   * `response`: interceptors get called with http `response` object. The function is free to
9973      *     modify the `response` object or create a new one. The function needs to return the `response`
9974      *     object directly, or as a promise containing the `response` or a new `response` object.
9975      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
9976      *     resolved with a rejection.
9977      *
9978      *
9979      * ```js
9980      *   // register the interceptor as a service
9981      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
9982      *     return {
9983      *       // optional method
9984      *       'request': function(config) {
9985      *         // do something on success
9986      *         return config;
9987      *       },
9988      *
9989      *       // optional method
9990      *      'requestError': function(rejection) {
9991      *         // do something on error
9992      *         if (canRecover(rejection)) {
9993      *           return responseOrNewPromise
9994      *         }
9995      *         return $q.reject(rejection);
9996      *       },
9997      *
9998      *
9999      *
10000      *       // optional method
10001      *       'response': function(response) {
10002      *         // do something on success
10003      *         return response;
10004      *       },
10005      *
10006      *       // optional method
10007      *      'responseError': function(rejection) {
10008      *         // do something on error
10009      *         if (canRecover(rejection)) {
10010      *           return responseOrNewPromise
10011      *         }
10012      *         return $q.reject(rejection);
10013      *       }
10014      *     };
10015      *   });
10016      *
10017      *   $httpProvider.interceptors.push('myHttpInterceptor');
10018      *
10019      *
10020      *   // alternatively, register the interceptor via an anonymous factory
10021      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
10022      *     return {
10023      *      'request': function(config) {
10024      *          // same as above
10025      *       },
10026      *
10027      *       'response': function(response) {
10028      *          // same as above
10029      *       }
10030      *     };
10031      *   });
10032      * ```
10033      *
10034      * ## Security Considerations
10035      *
10036      * When designing web applications, consider security threats from:
10037      *
10038      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10039      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
10040      *
10041      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
10042      * pre-configured with strategies that address these issues, but for this to work backend server
10043      * cooperation is required.
10044      *
10045      * ### JSON Vulnerability Protection
10046      *
10047      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10048      * allows third party website to turn your JSON resource URL into
10049      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
10050      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
10051      * Angular will automatically strip the prefix before processing it as JSON.
10052      *
10053      * For example if your server needs to return:
10054      * ```js
10055      * ['one','two']
10056      * ```
10057      *
10058      * which is vulnerable to attack, your server can return:
10059      * ```js
10060      * )]}',
10061      * ['one','two']
10062      * ```
10063      *
10064      * Angular will strip the prefix, before processing the JSON.
10065      *
10066      *
10067      * ### Cross Site Request Forgery (XSRF) Protection
10068      *
10069      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
10070      * an unauthorized site can gain your user's private data. Angular provides a mechanism
10071      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
10072      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
10073      * JavaScript that runs on your domain could read the cookie, your server can be assured that
10074      * the XHR came from JavaScript running on your domain. The header will not be set for
10075      * cross-domain requests.
10076      *
10077      * To take advantage of this, your server needs to set a token in a JavaScript readable session
10078      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
10079      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
10080      * that only JavaScript running on your domain could have sent the request. The token must be
10081      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
10082      * making up its own tokens). We recommend that the token is a digest of your site's
10083      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
10084      * for added security.
10085      *
10086      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
10087      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
10088      * or the per-request config object.
10089      *
10090      * In order to prevent collisions in environments where multiple Angular apps share the
10091      * same domain or subdomain, we recommend that each application uses unique cookie name.
10092      *
10093      * @param {object} config Object describing the request to be made and how it should be
10094      *    processed. The object has following properties:
10095      *
10096      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
10097      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
10098      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
10099      *      with the `paramSerializer` and appended as GET parameters.
10100      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
10101      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
10102      *      HTTP headers to send to the server. If the return value of a function is null, the
10103      *      header will not be sent. Functions accept a config object as an argument.
10104      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10105      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10106      *    - **transformRequest** –
10107      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
10108      *      transform function or an array of such functions. The transform function takes the http
10109      *      request body and headers and returns its transformed (typically serialized) version.
10110      *      See {@link ng.$http#overriding-the-default-transformations-per-request
10111      *      Overriding the Default Transformations}
10112      *    - **transformResponse** –
10113      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
10114      *      transform function or an array of such functions. The transform function takes the http
10115      *      response body, headers and status and returns its transformed (typically deserialized) version.
10116      *      See {@link ng.$http#overriding-the-default-transformations-per-request
10117      *      Overriding the Default TransformationjqLiks}
10118      *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
10119      *      prepare the string representation of request parameters (specified as an object).
10120      *      If specified as string, it is interpreted as function registered with the
10121      *      {@link $injector $injector}, which means you can create your own serializer
10122      *      by registering it as a {@link auto.$provide#service service}.
10123      *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
10124      *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
10125      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
10126      *      GET request, otherwise if a cache instance built with
10127      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
10128      *      caching.
10129      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
10130      *      that should abort the request when resolved.
10131      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
10132      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
10133      *      for more information.
10134      *    - **responseType** - `{string}` - see
10135      *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
10136      *
10137      * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
10138      *                        when the request succeeds or fails.
10139      *
10140      *
10141      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
10142      *   requests. This is primarily meant to be used for debugging purposes.
10143      *
10144      *
10145      * @example
10146 <example module="httpExample">
10147 <file name="index.html">
10148   <div ng-controller="FetchController">
10149     <select ng-model="method" aria-label="Request method">
10150       <option>GET</option>
10151       <option>JSONP</option>
10152     </select>
10153     <input type="text" ng-model="url" size="80" aria-label="URL" />
10154     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
10155     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
10156     <button id="samplejsonpbtn"
10157       ng-click="updateModel('JSONP',
10158                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
10159       Sample JSONP
10160     </button>
10161     <button id="invalidjsonpbtn"
10162       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
10163         Invalid JSONP
10164       </button>
10165     <pre>http status code: {{status}}</pre>
10166     <pre>http response data: {{data}}</pre>
10167   </div>
10168 </file>
10169 <file name="script.js">
10170   angular.module('httpExample', [])
10171     .controller('FetchController', ['$scope', '$http', '$templateCache',
10172       function($scope, $http, $templateCache) {
10173         $scope.method = 'GET';
10174         $scope.url = 'http-hello.html';
10175
10176         $scope.fetch = function() {
10177           $scope.code = null;
10178           $scope.response = null;
10179
10180           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
10181             then(function(response) {
10182               $scope.status = response.status;
10183               $scope.data = response.data;
10184             }, function(response) {
10185               $scope.data = response.data || "Request failed";
10186               $scope.status = response.status;
10187           });
10188         };
10189
10190         $scope.updateModel = function(method, url) {
10191           $scope.method = method;
10192           $scope.url = url;
10193         };
10194       }]);
10195 </file>
10196 <file name="http-hello.html">
10197   Hello, $http!
10198 </file>
10199 <file name="protractor.js" type="protractor">
10200   var status = element(by.binding('status'));
10201   var data = element(by.binding('data'));
10202   var fetchBtn = element(by.id('fetchbtn'));
10203   var sampleGetBtn = element(by.id('samplegetbtn'));
10204   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
10205   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
10206
10207   it('should make an xhr GET request', function() {
10208     sampleGetBtn.click();
10209     fetchBtn.click();
10210     expect(status.getText()).toMatch('200');
10211     expect(data.getText()).toMatch(/Hello, \$http!/);
10212   });
10213
10214 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
10215 // it('should make a JSONP request to angularjs.org', function() {
10216 //   sampleJsonpBtn.click();
10217 //   fetchBtn.click();
10218 //   expect(status.getText()).toMatch('200');
10219 //   expect(data.getText()).toMatch(/Super Hero!/);
10220 // });
10221
10222   it('should make JSONP request to invalid URL and invoke the error handler',
10223       function() {
10224     invalidJsonpBtn.click();
10225     fetchBtn.click();
10226     expect(status.getText()).toMatch('0');
10227     expect(data.getText()).toMatch('Request failed');
10228   });
10229 </file>
10230 </example>
10231      */
10232     function $http(requestConfig) {
10233
10234       if (!angular.isObject(requestConfig)) {
10235         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
10236       }
10237
10238       var config = extend({
10239         method: 'get',
10240         transformRequest: defaults.transformRequest,
10241         transformResponse: defaults.transformResponse,
10242         paramSerializer: defaults.paramSerializer
10243       }, requestConfig);
10244
10245       config.headers = mergeHeaders(requestConfig);
10246       config.method = uppercase(config.method);
10247       config.paramSerializer = isString(config.paramSerializer) ?
10248         $injector.get(config.paramSerializer) : config.paramSerializer;
10249
10250       var serverRequest = function(config) {
10251         var headers = config.headers;
10252         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
10253
10254         // strip content-type if data is undefined
10255         if (isUndefined(reqData)) {
10256           forEach(headers, function(value, header) {
10257             if (lowercase(header) === 'content-type') {
10258                 delete headers[header];
10259             }
10260           });
10261         }
10262
10263         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
10264           config.withCredentials = defaults.withCredentials;
10265         }
10266
10267         // send request
10268         return sendReq(config, reqData).then(transformResponse, transformResponse);
10269       };
10270
10271       var chain = [serverRequest, undefined];
10272       var promise = $q.when(config);
10273
10274       // apply interceptors
10275       forEach(reversedInterceptors, function(interceptor) {
10276         if (interceptor.request || interceptor.requestError) {
10277           chain.unshift(interceptor.request, interceptor.requestError);
10278         }
10279         if (interceptor.response || interceptor.responseError) {
10280           chain.push(interceptor.response, interceptor.responseError);
10281         }
10282       });
10283
10284       while (chain.length) {
10285         var thenFn = chain.shift();
10286         var rejectFn = chain.shift();
10287
10288         promise = promise.then(thenFn, rejectFn);
10289       }
10290
10291       if (useLegacyPromise) {
10292         promise.success = function(fn) {
10293           assertArgFn(fn, 'fn');
10294
10295           promise.then(function(response) {
10296             fn(response.data, response.status, response.headers, config);
10297           });
10298           return promise;
10299         };
10300
10301         promise.error = function(fn) {
10302           assertArgFn(fn, 'fn');
10303
10304           promise.then(null, function(response) {
10305             fn(response.data, response.status, response.headers, config);
10306           });
10307           return promise;
10308         };
10309       } else {
10310         promise.success = $httpMinErrLegacyFn('success');
10311         promise.error = $httpMinErrLegacyFn('error');
10312       }
10313
10314       return promise;
10315
10316       function transformResponse(response) {
10317         // make a copy since the response must be cacheable
10318         var resp = extend({}, response);
10319         resp.data = transformData(response.data, response.headers, response.status,
10320                                   config.transformResponse);
10321         return (isSuccess(response.status))
10322           ? resp
10323           : $q.reject(resp);
10324       }
10325
10326       function executeHeaderFns(headers, config) {
10327         var headerContent, processedHeaders = {};
10328
10329         forEach(headers, function(headerFn, header) {
10330           if (isFunction(headerFn)) {
10331             headerContent = headerFn(config);
10332             if (headerContent != null) {
10333               processedHeaders[header] = headerContent;
10334             }
10335           } else {
10336             processedHeaders[header] = headerFn;
10337           }
10338         });
10339
10340         return processedHeaders;
10341       }
10342
10343       function mergeHeaders(config) {
10344         var defHeaders = defaults.headers,
10345             reqHeaders = extend({}, config.headers),
10346             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
10347
10348         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10349
10350         // using for-in instead of forEach to avoid unecessary iteration after header has been found
10351         defaultHeadersIteration:
10352         for (defHeaderName in defHeaders) {
10353           lowercaseDefHeaderName = lowercase(defHeaderName);
10354
10355           for (reqHeaderName in reqHeaders) {
10356             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
10357               continue defaultHeadersIteration;
10358             }
10359           }
10360
10361           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
10362         }
10363
10364         // execute if header value is a function for merged headers
10365         return executeHeaderFns(reqHeaders, shallowCopy(config));
10366       }
10367     }
10368
10369     $http.pendingRequests = [];
10370
10371     /**
10372      * @ngdoc method
10373      * @name $http#get
10374      *
10375      * @description
10376      * Shortcut method to perform `GET` request.
10377      *
10378      * @param {string} url Relative or absolute URL specifying the destination of the request
10379      * @param {Object=} config Optional configuration object
10380      * @returns {HttpPromise} Future object
10381      */
10382
10383     /**
10384      * @ngdoc method
10385      * @name $http#delete
10386      *
10387      * @description
10388      * Shortcut method to perform `DELETE` request.
10389      *
10390      * @param {string} url Relative or absolute URL specifying the destination of the request
10391      * @param {Object=} config Optional configuration object
10392      * @returns {HttpPromise} Future object
10393      */
10394
10395     /**
10396      * @ngdoc method
10397      * @name $http#head
10398      *
10399      * @description
10400      * Shortcut method to perform `HEAD` request.
10401      *
10402      * @param {string} url Relative or absolute URL specifying the destination of the request
10403      * @param {Object=} config Optional configuration object
10404      * @returns {HttpPromise} Future object
10405      */
10406
10407     /**
10408      * @ngdoc method
10409      * @name $http#jsonp
10410      *
10411      * @description
10412      * Shortcut method to perform `JSONP` request.
10413      *
10414      * @param {string} url Relative or absolute URL specifying the destination of the request.
10415      *                     The name of the callback should be the string `JSON_CALLBACK`.
10416      * @param {Object=} config Optional configuration object
10417      * @returns {HttpPromise} Future object
10418      */
10419     createShortMethods('get', 'delete', 'head', 'jsonp');
10420
10421     /**
10422      * @ngdoc method
10423      * @name $http#post
10424      *
10425      * @description
10426      * Shortcut method to perform `POST` request.
10427      *
10428      * @param {string} url Relative or absolute URL specifying the destination of the request
10429      * @param {*} data Request content
10430      * @param {Object=} config Optional configuration object
10431      * @returns {HttpPromise} Future object
10432      */
10433
10434     /**
10435      * @ngdoc method
10436      * @name $http#put
10437      *
10438      * @description
10439      * Shortcut method to perform `PUT` request.
10440      *
10441      * @param {string} url Relative or absolute URL specifying the destination of the request
10442      * @param {*} data Request content
10443      * @param {Object=} config Optional configuration object
10444      * @returns {HttpPromise} Future object
10445      */
10446
10447      /**
10448       * @ngdoc method
10449       * @name $http#patch
10450       *
10451       * @description
10452       * Shortcut method to perform `PATCH` request.
10453       *
10454       * @param {string} url Relative or absolute URL specifying the destination of the request
10455       * @param {*} data Request content
10456       * @param {Object=} config Optional configuration object
10457       * @returns {HttpPromise} Future object
10458       */
10459     createShortMethodsWithData('post', 'put', 'patch');
10460
10461         /**
10462          * @ngdoc property
10463          * @name $http#defaults
10464          *
10465          * @description
10466          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
10467          * default headers, withCredentials as well as request and response transformations.
10468          *
10469          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
10470          */
10471     $http.defaults = defaults;
10472
10473
10474     return $http;
10475
10476
10477     function createShortMethods(names) {
10478       forEach(arguments, function(name) {
10479         $http[name] = function(url, config) {
10480           return $http(extend({}, config || {}, {
10481             method: name,
10482             url: url
10483           }));
10484         };
10485       });
10486     }
10487
10488
10489     function createShortMethodsWithData(name) {
10490       forEach(arguments, function(name) {
10491         $http[name] = function(url, data, config) {
10492           return $http(extend({}, config || {}, {
10493             method: name,
10494             url: url,
10495             data: data
10496           }));
10497         };
10498       });
10499     }
10500
10501
10502     /**
10503      * Makes the request.
10504      *
10505      * !!! ACCESSES CLOSURE VARS:
10506      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
10507      */
10508     function sendReq(config, reqData) {
10509       var deferred = $q.defer(),
10510           promise = deferred.promise,
10511           cache,
10512           cachedResp,
10513           reqHeaders = config.headers,
10514           url = buildUrl(config.url, config.paramSerializer(config.params));
10515
10516       $http.pendingRequests.push(config);
10517       promise.then(removePendingReq, removePendingReq);
10518
10519
10520       if ((config.cache || defaults.cache) && config.cache !== false &&
10521           (config.method === 'GET' || config.method === 'JSONP')) {
10522         cache = isObject(config.cache) ? config.cache
10523               : isObject(defaults.cache) ? defaults.cache
10524               : defaultCache;
10525       }
10526
10527       if (cache) {
10528         cachedResp = cache.get(url);
10529         if (isDefined(cachedResp)) {
10530           if (isPromiseLike(cachedResp)) {
10531             // cached request has already been sent, but there is no response yet
10532             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
10533           } else {
10534             // serving from cache
10535             if (isArray(cachedResp)) {
10536               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
10537             } else {
10538               resolvePromise(cachedResp, 200, {}, 'OK');
10539             }
10540           }
10541         } else {
10542           // put the promise for the non-transformed response into cache as a placeholder
10543           cache.put(url, promise);
10544         }
10545       }
10546
10547
10548       // if we won't have the response in cache, set the xsrf headers and
10549       // send the request to the backend
10550       if (isUndefined(cachedResp)) {
10551         var xsrfValue = urlIsSameOrigin(config.url)
10552             ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
10553             : undefined;
10554         if (xsrfValue) {
10555           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
10556         }
10557
10558         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
10559             config.withCredentials, config.responseType);
10560       }
10561
10562       return promise;
10563
10564
10565       /**
10566        * Callback registered to $httpBackend():
10567        *  - caches the response if desired
10568        *  - resolves the raw $http promise
10569        *  - calls $apply
10570        */
10571       function done(status, response, headersString, statusText) {
10572         if (cache) {
10573           if (isSuccess(status)) {
10574             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
10575           } else {
10576             // remove promise from the cache
10577             cache.remove(url);
10578           }
10579         }
10580
10581         function resolveHttpPromise() {
10582           resolvePromise(response, status, headersString, statusText);
10583         }
10584
10585         if (useApplyAsync) {
10586           $rootScope.$applyAsync(resolveHttpPromise);
10587         } else {
10588           resolveHttpPromise();
10589           if (!$rootScope.$$phase) $rootScope.$apply();
10590         }
10591       }
10592
10593
10594       /**
10595        * Resolves the raw $http promise.
10596        */
10597       function resolvePromise(response, status, headers, statusText) {
10598         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
10599         status = status >= -1 ? status : 0;
10600
10601         (isSuccess(status) ? deferred.resolve : deferred.reject)({
10602           data: response,
10603           status: status,
10604           headers: headersGetter(headers),
10605           config: config,
10606           statusText: statusText
10607         });
10608       }
10609
10610       function resolvePromiseWithResult(result) {
10611         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
10612       }
10613
10614       function removePendingReq() {
10615         var idx = $http.pendingRequests.indexOf(config);
10616         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
10617       }
10618     }
10619
10620
10621     function buildUrl(url, serializedParams) {
10622       if (serializedParams.length > 0) {
10623         url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
10624       }
10625       return url;
10626     }
10627   }];
10628 }
10629
10630 /**
10631  * @ngdoc service
10632  * @name $xhrFactory
10633  *
10634  * @description
10635  * Factory function used to create XMLHttpRequest objects.
10636  *
10637  * Replace or decorate this service to create your own custom XMLHttpRequest objects.
10638  *
10639  * ```
10640  * angular.module('myApp', [])
10641  * .factory('$xhrFactory', function() {
10642  *   return function createXhr(method, url) {
10643  *     return new window.XMLHttpRequest({mozSystem: true});
10644  *   };
10645  * });
10646  * ```
10647  *
10648  * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
10649  * @param {string} url URL of the request.
10650  */
10651 function $xhrFactoryProvider() {
10652   this.$get = function() {
10653     return function createXhr() {
10654       return new window.XMLHttpRequest();
10655     };
10656   };
10657 }
10658
10659 /**
10660  * @ngdoc service
10661  * @name $httpBackend
10662  * @requires $window
10663  * @requires $document
10664  * @requires $xhrFactory
10665  *
10666  * @description
10667  * HTTP backend used by the {@link ng.$http service} that delegates to
10668  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
10669  *
10670  * You should never need to use this service directly, instead use the higher-level abstractions:
10671  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
10672  *
10673  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
10674  * $httpBackend} which can be trained with responses.
10675  */
10676 function $HttpBackendProvider() {
10677   this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
10678     return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
10679   }];
10680 }
10681
10682 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
10683   // TODO(vojta): fix the signature
10684   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
10685     $browser.$$incOutstandingRequestCount();
10686     url = url || $browser.url();
10687
10688     if (lowercase(method) == 'jsonp') {
10689       var callbackId = '_' + (callbacks.counter++).toString(36);
10690       callbacks[callbackId] = function(data) {
10691         callbacks[callbackId].data = data;
10692         callbacks[callbackId].called = true;
10693       };
10694
10695       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
10696           callbackId, function(status, text) {
10697         completeRequest(callback, status, callbacks[callbackId].data, "", text);
10698         callbacks[callbackId] = noop;
10699       });
10700     } else {
10701
10702       var xhr = createXhr(method, url);
10703
10704       xhr.open(method, url, true);
10705       forEach(headers, function(value, key) {
10706         if (isDefined(value)) {
10707             xhr.setRequestHeader(key, value);
10708         }
10709       });
10710
10711       xhr.onload = function requestLoaded() {
10712         var statusText = xhr.statusText || '';
10713
10714         // responseText is the old-school way of retrieving response (supported by IE9)
10715         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
10716         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
10717
10718         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
10719         var status = xhr.status === 1223 ? 204 : xhr.status;
10720
10721         // fix status code when it is 0 (0 status is undocumented).
10722         // Occurs when accessing file resources or on Android 4.1 stock browser
10723         // while retrieving files from application cache.
10724         if (status === 0) {
10725           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
10726         }
10727
10728         completeRequest(callback,
10729             status,
10730             response,
10731             xhr.getAllResponseHeaders(),
10732             statusText);
10733       };
10734
10735       var requestError = function() {
10736         // The response is always empty
10737         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
10738         completeRequest(callback, -1, null, null, '');
10739       };
10740
10741       xhr.onerror = requestError;
10742       xhr.onabort = requestError;
10743
10744       if (withCredentials) {
10745         xhr.withCredentials = true;
10746       }
10747
10748       if (responseType) {
10749         try {
10750           xhr.responseType = responseType;
10751         } catch (e) {
10752           // WebKit added support for the json responseType value on 09/03/2013
10753           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
10754           // known to throw when setting the value "json" as the response type. Other older
10755           // browsers implementing the responseType
10756           //
10757           // The json response type can be ignored if not supported, because JSON payloads are
10758           // parsed on the client-side regardless.
10759           if (responseType !== 'json') {
10760             throw e;
10761           }
10762         }
10763       }
10764
10765       xhr.send(isUndefined(post) ? null : post);
10766     }
10767
10768     if (timeout > 0) {
10769       var timeoutId = $browserDefer(timeoutRequest, timeout);
10770     } else if (isPromiseLike(timeout)) {
10771       timeout.then(timeoutRequest);
10772     }
10773
10774
10775     function timeoutRequest() {
10776       jsonpDone && jsonpDone();
10777       xhr && xhr.abort();
10778     }
10779
10780     function completeRequest(callback, status, response, headersString, statusText) {
10781       // cancel timeout and subsequent timeout promise resolution
10782       if (isDefined(timeoutId)) {
10783         $browserDefer.cancel(timeoutId);
10784       }
10785       jsonpDone = xhr = null;
10786
10787       callback(status, response, headersString, statusText);
10788       $browser.$$completeOutstandingRequest(noop);
10789     }
10790   };
10791
10792   function jsonpReq(url, callbackId, done) {
10793     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
10794     // - fetches local scripts via XHR and evals them
10795     // - adds and immediately removes script elements from the document
10796     var script = rawDocument.createElement('script'), callback = null;
10797     script.type = "text/javascript";
10798     script.src = url;
10799     script.async = true;
10800
10801     callback = function(event) {
10802       removeEventListenerFn(script, "load", callback);
10803       removeEventListenerFn(script, "error", callback);
10804       rawDocument.body.removeChild(script);
10805       script = null;
10806       var status = -1;
10807       var text = "unknown";
10808
10809       if (event) {
10810         if (event.type === "load" && !callbacks[callbackId].called) {
10811           event = { type: "error" };
10812         }
10813         text = event.type;
10814         status = event.type === "error" ? 404 : 200;
10815       }
10816
10817       if (done) {
10818         done(status, text);
10819       }
10820     };
10821
10822     addEventListenerFn(script, "load", callback);
10823     addEventListenerFn(script, "error", callback);
10824     rawDocument.body.appendChild(script);
10825     return callback;
10826   }
10827 }
10828
10829 var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
10830 $interpolateMinErr.throwNoconcat = function(text) {
10831   throw $interpolateMinErr('noconcat',
10832       "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10833       "interpolations that concatenate multiple expressions when a trusted value is " +
10834       "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10835 };
10836
10837 $interpolateMinErr.interr = function(text, err) {
10838   return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
10839 };
10840
10841 /**
10842  * @ngdoc provider
10843  * @name $interpolateProvider
10844  *
10845  * @description
10846  *
10847  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10848  *
10849  * @example
10850 <example module="customInterpolationApp">
10851 <file name="index.html">
10852 <script>
10853   var customInterpolationApp = angular.module('customInterpolationApp', []);
10854
10855   customInterpolationApp.config(function($interpolateProvider) {
10856     $interpolateProvider.startSymbol('//');
10857     $interpolateProvider.endSymbol('//');
10858   });
10859
10860
10861   customInterpolationApp.controller('DemoController', function() {
10862       this.label = "This binding is brought you by // interpolation symbols.";
10863   });
10864 </script>
10865 <div ng-app="App" ng-controller="DemoController as demo">
10866     //demo.label//
10867 </div>
10868 </file>
10869 <file name="protractor.js" type="protractor">
10870   it('should interpolate binding with custom symbols', function() {
10871     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
10872   });
10873 </file>
10874 </example>
10875  */
10876 function $InterpolateProvider() {
10877   var startSymbol = '{{';
10878   var endSymbol = '}}';
10879
10880   /**
10881    * @ngdoc method
10882    * @name $interpolateProvider#startSymbol
10883    * @description
10884    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10885    *
10886    * @param {string=} value new value to set the starting symbol to.
10887    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10888    */
10889   this.startSymbol = function(value) {
10890     if (value) {
10891       startSymbol = value;
10892       return this;
10893     } else {
10894       return startSymbol;
10895     }
10896   };
10897
10898   /**
10899    * @ngdoc method
10900    * @name $interpolateProvider#endSymbol
10901    * @description
10902    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10903    *
10904    * @param {string=} value new value to set the ending symbol to.
10905    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10906    */
10907   this.endSymbol = function(value) {
10908     if (value) {
10909       endSymbol = value;
10910       return this;
10911     } else {
10912       return endSymbol;
10913     }
10914   };
10915
10916
10917   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10918     var startSymbolLength = startSymbol.length,
10919         endSymbolLength = endSymbol.length,
10920         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
10921         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
10922
10923     function escape(ch) {
10924       return '\\\\\\' + ch;
10925     }
10926
10927     function unescapeText(text) {
10928       return text.replace(escapedStartRegexp, startSymbol).
10929         replace(escapedEndRegexp, endSymbol);
10930     }
10931
10932     function stringify(value) {
10933       if (value == null) { // null || undefined
10934         return '';
10935       }
10936       switch (typeof value) {
10937         case 'string':
10938           break;
10939         case 'number':
10940           value = '' + value;
10941           break;
10942         default:
10943           value = toJson(value);
10944       }
10945
10946       return value;
10947     }
10948
10949     /**
10950      * @ngdoc service
10951      * @name $interpolate
10952      * @kind function
10953      *
10954      * @requires $parse
10955      * @requires $sce
10956      *
10957      * @description
10958      *
10959      * Compiles a string with markup into an interpolation function. This service is used by the
10960      * HTML {@link ng.$compile $compile} service for data binding. See
10961      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
10962      * interpolation markup.
10963      *
10964      *
10965      * ```js
10966      *   var $interpolate = ...; // injected
10967      *   var exp = $interpolate('Hello {{name | uppercase}}!');
10968      *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
10969      * ```
10970      *
10971      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
10972      * `true`, the interpolation function will return `undefined` unless all embedded expressions
10973      * evaluate to a value other than `undefined`.
10974      *
10975      * ```js
10976      *   var $interpolate = ...; // injected
10977      *   var context = {greeting: 'Hello', name: undefined };
10978      *
10979      *   // default "forgiving" mode
10980      *   var exp = $interpolate('{{greeting}} {{name}}!');
10981      *   expect(exp(context)).toEqual('Hello !');
10982      *
10983      *   // "allOrNothing" mode
10984      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
10985      *   expect(exp(context)).toBeUndefined();
10986      *   context.name = 'Angular';
10987      *   expect(exp(context)).toEqual('Hello Angular!');
10988      * ```
10989      *
10990      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
10991      *
10992      * ####Escaped Interpolation
10993      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
10994      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
10995      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
10996      * or binding.
10997      *
10998      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
10999      * degree, while also enabling code examples to work without relying on the
11000      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
11001      *
11002      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
11003      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
11004      * interpolation start/end markers with their escaped counterparts.**
11005      *
11006      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
11007      * output when the $interpolate service processes the text. So, for HTML elements interpolated
11008      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
11009      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
11010      * this is typically useful only when user-data is used in rendering a template from the server, or
11011      * when otherwise untrusted data is used by a directive.
11012      *
11013      * <example>
11014      *  <file name="index.html">
11015      *    <div ng-init="username='A user'">
11016      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
11017      *        </p>
11018      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
11019      *        application, but fails to accomplish their task, because the server has correctly
11020      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
11021      *        characters.</p>
11022      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
11023      *        from the database by an administrator.</p>
11024      *    </div>
11025      *  </file>
11026      * </example>
11027      *
11028      * @param {string} text The text with markup to interpolate.
11029      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
11030      *    embedded expression in order to return an interpolation function. Strings with no
11031      *    embedded expression will return null for the interpolation function.
11032      * @param {string=} trustedContext when provided, the returned function passes the interpolated
11033      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
11034      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
11035      *    provides Strict Contextual Escaping for details.
11036      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
11037      *    unless all embedded expressions evaluate to a value other than `undefined`.
11038      * @returns {function(context)} an interpolation function which is used to compute the
11039      *    interpolated string. The function has these parameters:
11040      *
11041      * - `context`: evaluation context for all expressions embedded in the interpolated text
11042      */
11043     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
11044       allOrNothing = !!allOrNothing;
11045       var startIndex,
11046           endIndex,
11047           index = 0,
11048           expressions = [],
11049           parseFns = [],
11050           textLength = text.length,
11051           exp,
11052           concat = [],
11053           expressionPositions = [];
11054
11055       while (index < textLength) {
11056         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
11057              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
11058           if (index !== startIndex) {
11059             concat.push(unescapeText(text.substring(index, startIndex)));
11060           }
11061           exp = text.substring(startIndex + startSymbolLength, endIndex);
11062           expressions.push(exp);
11063           parseFns.push($parse(exp, parseStringifyInterceptor));
11064           index = endIndex + endSymbolLength;
11065           expressionPositions.push(concat.length);
11066           concat.push('');
11067         } else {
11068           // we did not find an interpolation, so we have to add the remainder to the separators array
11069           if (index !== textLength) {
11070             concat.push(unescapeText(text.substring(index)));
11071           }
11072           break;
11073         }
11074       }
11075
11076       // Concatenating expressions makes it hard to reason about whether some combination of
11077       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
11078       // single expression be used for iframe[src], object[src], etc., we ensure that the value
11079       // that's used is assigned or constructed by some JS code somewhere that is more testable or
11080       // make it obvious that you bound the value to some user controlled value.  This helps reduce
11081       // the load when auditing for XSS issues.
11082       if (trustedContext && concat.length > 1) {
11083           $interpolateMinErr.throwNoconcat(text);
11084       }
11085
11086       if (!mustHaveExpression || expressions.length) {
11087         var compute = function(values) {
11088           for (var i = 0, ii = expressions.length; i < ii; i++) {
11089             if (allOrNothing && isUndefined(values[i])) return;
11090             concat[expressionPositions[i]] = values[i];
11091           }
11092           return concat.join('');
11093         };
11094
11095         var getValue = function(value) {
11096           return trustedContext ?
11097             $sce.getTrusted(trustedContext, value) :
11098             $sce.valueOf(value);
11099         };
11100
11101         return extend(function interpolationFn(context) {
11102             var i = 0;
11103             var ii = expressions.length;
11104             var values = new Array(ii);
11105
11106             try {
11107               for (; i < ii; i++) {
11108                 values[i] = parseFns[i](context);
11109               }
11110
11111               return compute(values);
11112             } catch (err) {
11113               $exceptionHandler($interpolateMinErr.interr(text, err));
11114             }
11115
11116           }, {
11117           // all of these properties are undocumented for now
11118           exp: text, //just for compatibility with regular watchers created via $watch
11119           expressions: expressions,
11120           $$watchDelegate: function(scope, listener) {
11121             var lastValue;
11122             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
11123               var currValue = compute(values);
11124               if (isFunction(listener)) {
11125                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
11126               }
11127               lastValue = currValue;
11128             });
11129           }
11130         });
11131       }
11132
11133       function parseStringifyInterceptor(value) {
11134         try {
11135           value = getValue(value);
11136           return allOrNothing && !isDefined(value) ? value : stringify(value);
11137         } catch (err) {
11138           $exceptionHandler($interpolateMinErr.interr(text, err));
11139         }
11140       }
11141     }
11142
11143
11144     /**
11145      * @ngdoc method
11146      * @name $interpolate#startSymbol
11147      * @description
11148      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
11149      *
11150      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
11151      * the symbol.
11152      *
11153      * @returns {string} start symbol.
11154      */
11155     $interpolate.startSymbol = function() {
11156       return startSymbol;
11157     };
11158
11159
11160     /**
11161      * @ngdoc method
11162      * @name $interpolate#endSymbol
11163      * @description
11164      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
11165      *
11166      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
11167      * the symbol.
11168      *
11169      * @returns {string} end symbol.
11170      */
11171     $interpolate.endSymbol = function() {
11172       return endSymbol;
11173     };
11174
11175     return $interpolate;
11176   }];
11177 }
11178
11179 function $IntervalProvider() {
11180   this.$get = ['$rootScope', '$window', '$q', '$$q',
11181        function($rootScope,   $window,   $q,   $$q) {
11182     var intervals = {};
11183
11184
11185      /**
11186       * @ngdoc service
11187       * @name $interval
11188       *
11189       * @description
11190       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
11191       * milliseconds.
11192       *
11193       * The return value of registering an interval function is a promise. This promise will be
11194       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
11195       * run indefinitely if `count` is not defined. The value of the notification will be the
11196       * number of iterations that have run.
11197       * To cancel an interval, call `$interval.cancel(promise)`.
11198       *
11199       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
11200       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
11201       * time.
11202       *
11203       * <div class="alert alert-warning">
11204       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
11205       * with them.  In particular they are not automatically destroyed when a controller's scope or a
11206       * directive's element are destroyed.
11207       * You should take this into consideration and make sure to always cancel the interval at the
11208       * appropriate moment.  See the example below for more details on how and when to do this.
11209       * </div>
11210       *
11211       * @param {function()} fn A function that should be called repeatedly.
11212       * @param {number} delay Number of milliseconds between each function call.
11213       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
11214       *   indefinitely.
11215       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
11216       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
11217       * @param {...*=} Pass additional parameters to the executed function.
11218       * @returns {promise} A promise which will be notified on each iteration.
11219       *
11220       * @example
11221       * <example module="intervalExample">
11222       * <file name="index.html">
11223       *   <script>
11224       *     angular.module('intervalExample', [])
11225       *       .controller('ExampleController', ['$scope', '$interval',
11226       *         function($scope, $interval) {
11227       *           $scope.format = 'M/d/yy h:mm:ss a';
11228       *           $scope.blood_1 = 100;
11229       *           $scope.blood_2 = 120;
11230       *
11231       *           var stop;
11232       *           $scope.fight = function() {
11233       *             // Don't start a new fight if we are already fighting
11234       *             if ( angular.isDefined(stop) ) return;
11235       *
11236       *             stop = $interval(function() {
11237       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
11238       *                 $scope.blood_1 = $scope.blood_1 - 3;
11239       *                 $scope.blood_2 = $scope.blood_2 - 4;
11240       *               } else {
11241       *                 $scope.stopFight();
11242       *               }
11243       *             }, 100);
11244       *           };
11245       *
11246       *           $scope.stopFight = function() {
11247       *             if (angular.isDefined(stop)) {
11248       *               $interval.cancel(stop);
11249       *               stop = undefined;
11250       *             }
11251       *           };
11252       *
11253       *           $scope.resetFight = function() {
11254       *             $scope.blood_1 = 100;
11255       *             $scope.blood_2 = 120;
11256       *           };
11257       *
11258       *           $scope.$on('$destroy', function() {
11259       *             // Make sure that the interval is destroyed too
11260       *             $scope.stopFight();
11261       *           });
11262       *         }])
11263       *       // Register the 'myCurrentTime' directive factory method.
11264       *       // We inject $interval and dateFilter service since the factory method is DI.
11265       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
11266       *         function($interval, dateFilter) {
11267       *           // return the directive link function. (compile function not needed)
11268       *           return function(scope, element, attrs) {
11269       *             var format,  // date format
11270       *                 stopTime; // so that we can cancel the time updates
11271       *
11272       *             // used to update the UI
11273       *             function updateTime() {
11274       *               element.text(dateFilter(new Date(), format));
11275       *             }
11276       *
11277       *             // watch the expression, and update the UI on change.
11278       *             scope.$watch(attrs.myCurrentTime, function(value) {
11279       *               format = value;
11280       *               updateTime();
11281       *             });
11282       *
11283       *             stopTime = $interval(updateTime, 1000);
11284       *
11285       *             // listen on DOM destroy (removal) event, and cancel the next UI update
11286       *             // to prevent updating time after the DOM element was removed.
11287       *             element.on('$destroy', function() {
11288       *               $interval.cancel(stopTime);
11289       *             });
11290       *           }
11291       *         }]);
11292       *   </script>
11293       *
11294       *   <div>
11295       *     <div ng-controller="ExampleController">
11296       *       <label>Date format: <input ng-model="format"></label> <hr/>
11297       *       Current time is: <span my-current-time="format"></span>
11298       *       <hr/>
11299       *       Blood 1 : <font color='red'>{{blood_1}}</font>
11300       *       Blood 2 : <font color='red'>{{blood_2}}</font>
11301       *       <button type="button" data-ng-click="fight()">Fight</button>
11302       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
11303       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
11304       *     </div>
11305       *   </div>
11306       *
11307       * </file>
11308       * </example>
11309       */
11310     function interval(fn, delay, count, invokeApply) {
11311       var hasParams = arguments.length > 4,
11312           args = hasParams ? sliceArgs(arguments, 4) : [],
11313           setInterval = $window.setInterval,
11314           clearInterval = $window.clearInterval,
11315           iteration = 0,
11316           skipApply = (isDefined(invokeApply) && !invokeApply),
11317           deferred = (skipApply ? $$q : $q).defer(),
11318           promise = deferred.promise;
11319
11320       count = isDefined(count) ? count : 0;
11321
11322       promise.then(null, null, (!hasParams) ? fn : function() {
11323         fn.apply(null, args);
11324       });
11325
11326       promise.$$intervalId = setInterval(function tick() {
11327         deferred.notify(iteration++);
11328
11329         if (count > 0 && iteration >= count) {
11330           deferred.resolve(iteration);
11331           clearInterval(promise.$$intervalId);
11332           delete intervals[promise.$$intervalId];
11333         }
11334
11335         if (!skipApply) $rootScope.$apply();
11336
11337       }, delay);
11338
11339       intervals[promise.$$intervalId] = deferred;
11340
11341       return promise;
11342     }
11343
11344
11345      /**
11346       * @ngdoc method
11347       * @name $interval#cancel
11348       *
11349       * @description
11350       * Cancels a task associated with the `promise`.
11351       *
11352       * @param {Promise=} promise returned by the `$interval` function.
11353       * @returns {boolean} Returns `true` if the task was successfully canceled.
11354       */
11355     interval.cancel = function(promise) {
11356       if (promise && promise.$$intervalId in intervals) {
11357         intervals[promise.$$intervalId].reject('canceled');
11358         $window.clearInterval(promise.$$intervalId);
11359         delete intervals[promise.$$intervalId];
11360         return true;
11361       }
11362       return false;
11363     };
11364
11365     return interval;
11366   }];
11367 }
11368
11369 /**
11370  * @ngdoc service
11371  * @name $locale
11372  *
11373  * @description
11374  * $locale service provides localization rules for various Angular components. As of right now the
11375  * only public api is:
11376  *
11377  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
11378  */
11379
11380 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
11381     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
11382 var $locationMinErr = minErr('$location');
11383
11384
11385 /**
11386  * Encode path using encodeUriSegment, ignoring forward slashes
11387  *
11388  * @param {string} path Path to encode
11389  * @returns {string}
11390  */
11391 function encodePath(path) {
11392   var segments = path.split('/'),
11393       i = segments.length;
11394
11395   while (i--) {
11396     segments[i] = encodeUriSegment(segments[i]);
11397   }
11398
11399   return segments.join('/');
11400 }
11401
11402 function parseAbsoluteUrl(absoluteUrl, locationObj) {
11403   var parsedUrl = urlResolve(absoluteUrl);
11404
11405   locationObj.$$protocol = parsedUrl.protocol;
11406   locationObj.$$host = parsedUrl.hostname;
11407   locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
11408 }
11409
11410
11411 function parseAppUrl(relativeUrl, locationObj) {
11412   var prefixed = (relativeUrl.charAt(0) !== '/');
11413   if (prefixed) {
11414     relativeUrl = '/' + relativeUrl;
11415   }
11416   var match = urlResolve(relativeUrl);
11417   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
11418       match.pathname.substring(1) : match.pathname);
11419   locationObj.$$search = parseKeyValue(match.search);
11420   locationObj.$$hash = decodeURIComponent(match.hash);
11421
11422   // make sure path starts with '/';
11423   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
11424     locationObj.$$path = '/' + locationObj.$$path;
11425   }
11426 }
11427
11428
11429 /**
11430  *
11431  * @param {string} begin
11432  * @param {string} whole
11433  * @returns {string} returns text from whole after begin or undefined if it does not begin with
11434  *                   expected string.
11435  */
11436 function beginsWith(begin, whole) {
11437   if (whole.indexOf(begin) === 0) {
11438     return whole.substr(begin.length);
11439   }
11440 }
11441
11442
11443 function stripHash(url) {
11444   var index = url.indexOf('#');
11445   return index == -1 ? url : url.substr(0, index);
11446 }
11447
11448 function trimEmptyHash(url) {
11449   return url.replace(/(#.+)|#$/, '$1');
11450 }
11451
11452
11453 function stripFile(url) {
11454   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
11455 }
11456
11457 /* return the server only (scheme://host:port) */
11458 function serverBase(url) {
11459   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
11460 }
11461
11462
11463 /**
11464  * LocationHtml5Url represents an url
11465  * This object is exposed as $location service when HTML5 mode is enabled and supported
11466  *
11467  * @constructor
11468  * @param {string} appBase application base URL
11469  * @param {string} appBaseNoFile application base URL stripped of any filename
11470  * @param {string} basePrefix url path prefix
11471  */
11472 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
11473   this.$$html5 = true;
11474   basePrefix = basePrefix || '';
11475   parseAbsoluteUrl(appBase, this);
11476
11477
11478   /**
11479    * Parse given html5 (regular) url string into properties
11480    * @param {string} url HTML5 url
11481    * @private
11482    */
11483   this.$$parse = function(url) {
11484     var pathUrl = beginsWith(appBaseNoFile, url);
11485     if (!isString(pathUrl)) {
11486       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
11487           appBaseNoFile);
11488     }
11489
11490     parseAppUrl(pathUrl, this);
11491
11492     if (!this.$$path) {
11493       this.$$path = '/';
11494     }
11495
11496     this.$$compose();
11497   };
11498
11499   /**
11500    * Compose url and update `absUrl` property
11501    * @private
11502    */
11503   this.$$compose = function() {
11504     var search = toKeyValue(this.$$search),
11505         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11506
11507     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11508     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
11509   };
11510
11511   this.$$parseLinkUrl = function(url, relHref) {
11512     if (relHref && relHref[0] === '#') {
11513       // special case for links to hash fragments:
11514       // keep the old url and only replace the hash fragment
11515       this.hash(relHref.slice(1));
11516       return true;
11517     }
11518     var appUrl, prevAppUrl;
11519     var rewrittenUrl;
11520
11521     if (isDefined(appUrl = beginsWith(appBase, url))) {
11522       prevAppUrl = appUrl;
11523       if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
11524         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
11525       } else {
11526         rewrittenUrl = appBase + prevAppUrl;
11527       }
11528     } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
11529       rewrittenUrl = appBaseNoFile + appUrl;
11530     } else if (appBaseNoFile == url + '/') {
11531       rewrittenUrl = appBaseNoFile;
11532     }
11533     if (rewrittenUrl) {
11534       this.$$parse(rewrittenUrl);
11535     }
11536     return !!rewrittenUrl;
11537   };
11538 }
11539
11540
11541 /**
11542  * LocationHashbangUrl represents url
11543  * This object is exposed as $location service when developer doesn't opt into html5 mode.
11544  * It also serves as the base class for html5 mode fallback on legacy browsers.
11545  *
11546  * @constructor
11547  * @param {string} appBase application base URL
11548  * @param {string} appBaseNoFile application base URL stripped of any filename
11549  * @param {string} hashPrefix hashbang prefix
11550  */
11551 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
11552
11553   parseAbsoluteUrl(appBase, this);
11554
11555
11556   /**
11557    * Parse given hashbang url into properties
11558    * @param {string} url Hashbang url
11559    * @private
11560    */
11561   this.$$parse = function(url) {
11562     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
11563     var withoutHashUrl;
11564
11565     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
11566
11567       // The rest of the url starts with a hash so we have
11568       // got either a hashbang path or a plain hash fragment
11569       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
11570       if (isUndefined(withoutHashUrl)) {
11571         // There was no hashbang prefix so we just have a hash fragment
11572         withoutHashUrl = withoutBaseUrl;
11573       }
11574
11575     } else {
11576       // There was no hashbang path nor hash fragment:
11577       // If we are in HTML5 mode we use what is left as the path;
11578       // Otherwise we ignore what is left
11579       if (this.$$html5) {
11580         withoutHashUrl = withoutBaseUrl;
11581       } else {
11582         withoutHashUrl = '';
11583         if (isUndefined(withoutBaseUrl)) {
11584           appBase = url;
11585           this.replace();
11586         }
11587       }
11588     }
11589
11590     parseAppUrl(withoutHashUrl, this);
11591
11592     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
11593
11594     this.$$compose();
11595
11596     /*
11597      * In Windows, on an anchor node on documents loaded from
11598      * the filesystem, the browser will return a pathname
11599      * prefixed with the drive name ('/C:/path') when a
11600      * pathname without a drive is set:
11601      *  * a.setAttribute('href', '/foo')
11602      *   * a.pathname === '/C:/foo' //true
11603      *
11604      * Inside of Angular, we're always using pathnames that
11605      * do not include drive names for routing.
11606      */
11607     function removeWindowsDriveName(path, url, base) {
11608       /*
11609       Matches paths for file protocol on windows,
11610       such as /C:/foo/bar, and captures only /foo/bar.
11611       */
11612       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
11613
11614       var firstPathSegmentMatch;
11615
11616       //Get the relative path from the input URL.
11617       if (url.indexOf(base) === 0) {
11618         url = url.replace(base, '');
11619       }
11620
11621       // The input URL intentionally contains a first path segment that ends with a colon.
11622       if (windowsFilePathExp.exec(url)) {
11623         return path;
11624       }
11625
11626       firstPathSegmentMatch = windowsFilePathExp.exec(path);
11627       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
11628     }
11629   };
11630
11631   /**
11632    * Compose hashbang url and update `absUrl` property
11633    * @private
11634    */
11635   this.$$compose = function() {
11636     var search = toKeyValue(this.$$search),
11637         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11638
11639     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11640     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
11641   };
11642
11643   this.$$parseLinkUrl = function(url, relHref) {
11644     if (stripHash(appBase) == stripHash(url)) {
11645       this.$$parse(url);
11646       return true;
11647     }
11648     return false;
11649   };
11650 }
11651
11652
11653 /**
11654  * LocationHashbangUrl represents url
11655  * This object is exposed as $location service when html5 history api is enabled but the browser
11656  * does not support it.
11657  *
11658  * @constructor
11659  * @param {string} appBase application base URL
11660  * @param {string} appBaseNoFile application base URL stripped of any filename
11661  * @param {string} hashPrefix hashbang prefix
11662  */
11663 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
11664   this.$$html5 = true;
11665   LocationHashbangUrl.apply(this, arguments);
11666
11667   this.$$parseLinkUrl = function(url, relHref) {
11668     if (relHref && relHref[0] === '#') {
11669       // special case for links to hash fragments:
11670       // keep the old url and only replace the hash fragment
11671       this.hash(relHref.slice(1));
11672       return true;
11673     }
11674
11675     var rewrittenUrl;
11676     var appUrl;
11677
11678     if (appBase == stripHash(url)) {
11679       rewrittenUrl = url;
11680     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
11681       rewrittenUrl = appBase + hashPrefix + appUrl;
11682     } else if (appBaseNoFile === url + '/') {
11683       rewrittenUrl = appBaseNoFile;
11684     }
11685     if (rewrittenUrl) {
11686       this.$$parse(rewrittenUrl);
11687     }
11688     return !!rewrittenUrl;
11689   };
11690
11691   this.$$compose = function() {
11692     var search = toKeyValue(this.$$search),
11693         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11694
11695     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11696     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
11697     this.$$absUrl = appBase + hashPrefix + this.$$url;
11698   };
11699
11700 }
11701
11702
11703 var locationPrototype = {
11704
11705   /**
11706    * Are we in html5 mode?
11707    * @private
11708    */
11709   $$html5: false,
11710
11711   /**
11712    * Has any change been replacing?
11713    * @private
11714    */
11715   $$replace: false,
11716
11717   /**
11718    * @ngdoc method
11719    * @name $location#absUrl
11720    *
11721    * @description
11722    * This method is getter only.
11723    *
11724    * Return full url representation with all segments encoded according to rules specified in
11725    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
11726    *
11727    *
11728    * ```js
11729    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11730    * var absUrl = $location.absUrl();
11731    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
11732    * ```
11733    *
11734    * @return {string} full url
11735    */
11736   absUrl: locationGetter('$$absUrl'),
11737
11738   /**
11739    * @ngdoc method
11740    * @name $location#url
11741    *
11742    * @description
11743    * This method is getter / setter.
11744    *
11745    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
11746    *
11747    * Change path, search and hash, when called with parameter and return `$location`.
11748    *
11749    *
11750    * ```js
11751    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11752    * var url = $location.url();
11753    * // => "/some/path?foo=bar&baz=xoxo"
11754    * ```
11755    *
11756    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
11757    * @return {string} url
11758    */
11759   url: function(url) {
11760     if (isUndefined(url)) {
11761       return this.$$url;
11762     }
11763
11764     var match = PATH_MATCH.exec(url);
11765     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
11766     if (match[2] || match[1] || url === '') this.search(match[3] || '');
11767     this.hash(match[5] || '');
11768
11769     return this;
11770   },
11771
11772   /**
11773    * @ngdoc method
11774    * @name $location#protocol
11775    *
11776    * @description
11777    * This method is getter only.
11778    *
11779    * Return protocol of current url.
11780    *
11781    *
11782    * ```js
11783    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11784    * var protocol = $location.protocol();
11785    * // => "http"
11786    * ```
11787    *
11788    * @return {string} protocol of current url
11789    */
11790   protocol: locationGetter('$$protocol'),
11791
11792   /**
11793    * @ngdoc method
11794    * @name $location#host
11795    *
11796    * @description
11797    * This method is getter only.
11798    *
11799    * Return host of current url.
11800    *
11801    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
11802    *
11803    *
11804    * ```js
11805    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11806    * var host = $location.host();
11807    * // => "example.com"
11808    *
11809    * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
11810    * host = $location.host();
11811    * // => "example.com"
11812    * host = location.host;
11813    * // => "example.com:8080"
11814    * ```
11815    *
11816    * @return {string} host of current url.
11817    */
11818   host: locationGetter('$$host'),
11819
11820   /**
11821    * @ngdoc method
11822    * @name $location#port
11823    *
11824    * @description
11825    * This method is getter only.
11826    *
11827    * Return port of current url.
11828    *
11829    *
11830    * ```js
11831    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11832    * var port = $location.port();
11833    * // => 80
11834    * ```
11835    *
11836    * @return {Number} port
11837    */
11838   port: locationGetter('$$port'),
11839
11840   /**
11841    * @ngdoc method
11842    * @name $location#path
11843    *
11844    * @description
11845    * This method is getter / setter.
11846    *
11847    * Return path of current url when called without any parameter.
11848    *
11849    * Change path when called with parameter and return `$location`.
11850    *
11851    * Note: Path should always begin with forward slash (/), this method will add the forward slash
11852    * if it is missing.
11853    *
11854    *
11855    * ```js
11856    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11857    * var path = $location.path();
11858    * // => "/some/path"
11859    * ```
11860    *
11861    * @param {(string|number)=} path New path
11862    * @return {string} path
11863    */
11864   path: locationGetterSetter('$$path', function(path) {
11865     path = path !== null ? path.toString() : '';
11866     return path.charAt(0) == '/' ? path : '/' + path;
11867   }),
11868
11869   /**
11870    * @ngdoc method
11871    * @name $location#search
11872    *
11873    * @description
11874    * This method is getter / setter.
11875    *
11876    * Return search part (as object) of current url when called without any parameter.
11877    *
11878    * Change search part when called with parameter and return `$location`.
11879    *
11880    *
11881    * ```js
11882    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11883    * var searchObject = $location.search();
11884    * // => {foo: 'bar', baz: 'xoxo'}
11885    *
11886    * // set foo to 'yipee'
11887    * $location.search('foo', 'yipee');
11888    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11889    * ```
11890    *
11891    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11892    * hash object.
11893    *
11894    * When called with a single argument the method acts as a setter, setting the `search` component
11895    * of `$location` to the specified value.
11896    *
11897    * If the argument is a hash object containing an array of values, these values will be encoded
11898    * as duplicate search parameters in the url.
11899    *
11900    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11901    * will override only a single search property.
11902    *
11903    * If `paramValue` is an array, it will override the property of the `search` component of
11904    * `$location` specified via the first argument.
11905    *
11906    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11907    *
11908    * If `paramValue` is `true`, the property specified via the first argument will be added with no
11909    * value nor trailing equal sign.
11910    *
11911    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11912    * one or more arguments returns `$location` object itself.
11913    */
11914   search: function(search, paramValue) {
11915     switch (arguments.length) {
11916       case 0:
11917         return this.$$search;
11918       case 1:
11919         if (isString(search) || isNumber(search)) {
11920           search = search.toString();
11921           this.$$search = parseKeyValue(search);
11922         } else if (isObject(search)) {
11923           search = copy(search, {});
11924           // remove object undefined or null properties
11925           forEach(search, function(value, key) {
11926             if (value == null) delete search[key];
11927           });
11928
11929           this.$$search = search;
11930         } else {
11931           throw $locationMinErr('isrcharg',
11932               'The first argument of the `$location#search()` call must be a string or an object.');
11933         }
11934         break;
11935       default:
11936         if (isUndefined(paramValue) || paramValue === null) {
11937           delete this.$$search[search];
11938         } else {
11939           this.$$search[search] = paramValue;
11940         }
11941     }
11942
11943     this.$$compose();
11944     return this;
11945   },
11946
11947   /**
11948    * @ngdoc method
11949    * @name $location#hash
11950    *
11951    * @description
11952    * This method is getter / setter.
11953    *
11954    * Returns the hash fragment when called without any parameters.
11955    *
11956    * Changes the hash fragment when called with a parameter and returns `$location`.
11957    *
11958    *
11959    * ```js
11960    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
11961    * var hash = $location.hash();
11962    * // => "hashValue"
11963    * ```
11964    *
11965    * @param {(string|number)=} hash New hash fragment
11966    * @return {string} hash
11967    */
11968   hash: locationGetterSetter('$$hash', function(hash) {
11969     return hash !== null ? hash.toString() : '';
11970   }),
11971
11972   /**
11973    * @ngdoc method
11974    * @name $location#replace
11975    *
11976    * @description
11977    * If called, all changes to $location during the current `$digest` will replace the current history
11978    * record, instead of adding a new one.
11979    */
11980   replace: function() {
11981     this.$$replace = true;
11982     return this;
11983   }
11984 };
11985
11986 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
11987   Location.prototype = Object.create(locationPrototype);
11988
11989   /**
11990    * @ngdoc method
11991    * @name $location#state
11992    *
11993    * @description
11994    * This method is getter / setter.
11995    *
11996    * Return the history state object when called without any parameter.
11997    *
11998    * Change the history state object when called with one parameter and return `$location`.
11999    * The state object is later passed to `pushState` or `replaceState`.
12000    *
12001    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
12002    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
12003    * older browsers (like IE9 or Android < 4.0), don't use this method.
12004    *
12005    * @param {object=} state State object for pushState or replaceState
12006    * @return {object} state
12007    */
12008   Location.prototype.state = function(state) {
12009     if (!arguments.length) {
12010       return this.$$state;
12011     }
12012
12013     if (Location !== LocationHtml5Url || !this.$$html5) {
12014       throw $locationMinErr('nostate', 'History API state support is available only ' +
12015         'in HTML5 mode and only in browsers supporting HTML5 History API');
12016     }
12017     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
12018     // but we're changing the $$state reference to $browser.state() during the $digest
12019     // so the modification window is narrow.
12020     this.$$state = isUndefined(state) ? null : state;
12021
12022     return this;
12023   };
12024 });
12025
12026
12027 function locationGetter(property) {
12028   return function() {
12029     return this[property];
12030   };
12031 }
12032
12033
12034 function locationGetterSetter(property, preprocess) {
12035   return function(value) {
12036     if (isUndefined(value)) {
12037       return this[property];
12038     }
12039
12040     this[property] = preprocess(value);
12041     this.$$compose();
12042
12043     return this;
12044   };
12045 }
12046
12047
12048 /**
12049  * @ngdoc service
12050  * @name $location
12051  *
12052  * @requires $rootElement
12053  *
12054  * @description
12055  * The $location service parses the URL in the browser address bar (based on the
12056  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
12057  * available to your application. Changes to the URL in the address bar are reflected into
12058  * $location service and changes to $location are reflected into the browser address bar.
12059  *
12060  * **The $location service:**
12061  *
12062  * - Exposes the current URL in the browser address bar, so you can
12063  *   - Watch and observe the URL.
12064  *   - Change the URL.
12065  * - Synchronizes the URL with the browser when the user
12066  *   - Changes the address bar.
12067  *   - Clicks the back or forward button (or clicks a History link).
12068  *   - Clicks on a link.
12069  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
12070  *
12071  * For more information see {@link guide/$location Developer Guide: Using $location}
12072  */
12073
12074 /**
12075  * @ngdoc provider
12076  * @name $locationProvider
12077  * @description
12078  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
12079  */
12080 function $LocationProvider() {
12081   var hashPrefix = '',
12082       html5Mode = {
12083         enabled: false,
12084         requireBase: true,
12085         rewriteLinks: true
12086       };
12087
12088   /**
12089    * @ngdoc method
12090    * @name $locationProvider#hashPrefix
12091    * @description
12092    * @param {string=} prefix Prefix for hash part (containing path and search)
12093    * @returns {*} current value if used as getter or itself (chaining) if used as setter
12094    */
12095   this.hashPrefix = function(prefix) {
12096     if (isDefined(prefix)) {
12097       hashPrefix = prefix;
12098       return this;
12099     } else {
12100       return hashPrefix;
12101     }
12102   };
12103
12104   /**
12105    * @ngdoc method
12106    * @name $locationProvider#html5Mode
12107    * @description
12108    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
12109    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
12110    *   properties:
12111    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
12112    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
12113    *     support `pushState`.
12114    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
12115    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
12116    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
12117    *     See the {@link guide/$location $location guide for more information}
12118    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
12119    *     enables/disables url rewriting for relative links.
12120    *
12121    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
12122    */
12123   this.html5Mode = function(mode) {
12124     if (isBoolean(mode)) {
12125       html5Mode.enabled = mode;
12126       return this;
12127     } else if (isObject(mode)) {
12128
12129       if (isBoolean(mode.enabled)) {
12130         html5Mode.enabled = mode.enabled;
12131       }
12132
12133       if (isBoolean(mode.requireBase)) {
12134         html5Mode.requireBase = mode.requireBase;
12135       }
12136
12137       if (isBoolean(mode.rewriteLinks)) {
12138         html5Mode.rewriteLinks = mode.rewriteLinks;
12139       }
12140
12141       return this;
12142     } else {
12143       return html5Mode;
12144     }
12145   };
12146
12147   /**
12148    * @ngdoc event
12149    * @name $location#$locationChangeStart
12150    * @eventType broadcast on root scope
12151    * @description
12152    * Broadcasted before a URL will change.
12153    *
12154    * This change can be prevented by calling
12155    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
12156    * details about event object. Upon successful change
12157    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
12158    *
12159    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12160    * the browser supports the HTML5 History API.
12161    *
12162    * @param {Object} angularEvent Synthetic event object.
12163    * @param {string} newUrl New URL
12164    * @param {string=} oldUrl URL that was before it was changed.
12165    * @param {string=} newState New history state object
12166    * @param {string=} oldState History state object that was before it was changed.
12167    */
12168
12169   /**
12170    * @ngdoc event
12171    * @name $location#$locationChangeSuccess
12172    * @eventType broadcast on root scope
12173    * @description
12174    * Broadcasted after a URL was changed.
12175    *
12176    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12177    * the browser supports the HTML5 History API.
12178    *
12179    * @param {Object} angularEvent Synthetic event object.
12180    * @param {string} newUrl New URL
12181    * @param {string=} oldUrl URL that was before it was changed.
12182    * @param {string=} newState New history state object
12183    * @param {string=} oldState History state object that was before it was changed.
12184    */
12185
12186   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
12187       function($rootScope, $browser, $sniffer, $rootElement, $window) {
12188     var $location,
12189         LocationMode,
12190         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
12191         initialUrl = $browser.url(),
12192         appBase;
12193
12194     if (html5Mode.enabled) {
12195       if (!baseHref && html5Mode.requireBase) {
12196         throw $locationMinErr('nobase',
12197           "$location in HTML5 mode requires a <base> tag to be present!");
12198       }
12199       appBase = serverBase(initialUrl) + (baseHref || '/');
12200       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
12201     } else {
12202       appBase = stripHash(initialUrl);
12203       LocationMode = LocationHashbangUrl;
12204     }
12205     var appBaseNoFile = stripFile(appBase);
12206
12207     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
12208     $location.$$parseLinkUrl(initialUrl, initialUrl);
12209
12210     $location.$$state = $browser.state();
12211
12212     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
12213
12214     function setBrowserUrlWithFallback(url, replace, state) {
12215       var oldUrl = $location.url();
12216       var oldState = $location.$$state;
12217       try {
12218         $browser.url(url, replace, state);
12219
12220         // Make sure $location.state() returns referentially identical (not just deeply equal)
12221         // state object; this makes possible quick checking if the state changed in the digest
12222         // loop. Checking deep equality would be too expensive.
12223         $location.$$state = $browser.state();
12224       } catch (e) {
12225         // Restore old values if pushState fails
12226         $location.url(oldUrl);
12227         $location.$$state = oldState;
12228
12229         throw e;
12230       }
12231     }
12232
12233     $rootElement.on('click', function(event) {
12234       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
12235       // currently we open nice url link and redirect then
12236
12237       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
12238
12239       var elm = jqLite(event.target);
12240
12241       // traverse the DOM up to find first A tag
12242       while (nodeName_(elm[0]) !== 'a') {
12243         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
12244         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
12245       }
12246
12247       var absHref = elm.prop('href');
12248       // get the actual href attribute - see
12249       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
12250       var relHref = elm.attr('href') || elm.attr('xlink:href');
12251
12252       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
12253         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
12254         // an animation.
12255         absHref = urlResolve(absHref.animVal).href;
12256       }
12257
12258       // Ignore when url is started with javascript: or mailto:
12259       if (IGNORE_URI_REGEXP.test(absHref)) return;
12260
12261       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
12262         if ($location.$$parseLinkUrl(absHref, relHref)) {
12263           // We do a preventDefault for all urls that are part of the angular application,
12264           // in html5mode and also without, so that we are able to abort navigation without
12265           // getting double entries in the location history.
12266           event.preventDefault();
12267           // update location manually
12268           if ($location.absUrl() != $browser.url()) {
12269             $rootScope.$apply();
12270             // hack to work around FF6 bug 684208 when scenario runner clicks on links
12271             $window.angular['ff-684208-preventDefault'] = true;
12272           }
12273         }
12274       }
12275     });
12276
12277
12278     // rewrite hashbang url <> html5 url
12279     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
12280       $browser.url($location.absUrl(), true);
12281     }
12282
12283     var initializing = true;
12284
12285     // update $location when $browser url changes
12286     $browser.onUrlChange(function(newUrl, newState) {
12287
12288       if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
12289         // If we are navigating outside of the app then force a reload
12290         $window.location.href = newUrl;
12291         return;
12292       }
12293
12294       $rootScope.$evalAsync(function() {
12295         var oldUrl = $location.absUrl();
12296         var oldState = $location.$$state;
12297         var defaultPrevented;
12298         newUrl = trimEmptyHash(newUrl);
12299         $location.$$parse(newUrl);
12300         $location.$$state = newState;
12301
12302         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12303             newState, oldState).defaultPrevented;
12304
12305         // if the location was changed by a `$locationChangeStart` handler then stop
12306         // processing this location change
12307         if ($location.absUrl() !== newUrl) return;
12308
12309         if (defaultPrevented) {
12310           $location.$$parse(oldUrl);
12311           $location.$$state = oldState;
12312           setBrowserUrlWithFallback(oldUrl, false, oldState);
12313         } else {
12314           initializing = false;
12315           afterLocationChange(oldUrl, oldState);
12316         }
12317       });
12318       if (!$rootScope.$$phase) $rootScope.$digest();
12319     });
12320
12321     // update browser
12322     $rootScope.$watch(function $locationWatch() {
12323       var oldUrl = trimEmptyHash($browser.url());
12324       var newUrl = trimEmptyHash($location.absUrl());
12325       var oldState = $browser.state();
12326       var currentReplace = $location.$$replace;
12327       var urlOrStateChanged = oldUrl !== newUrl ||
12328         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
12329
12330       if (initializing || urlOrStateChanged) {
12331         initializing = false;
12332
12333         $rootScope.$evalAsync(function() {
12334           var newUrl = $location.absUrl();
12335           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12336               $location.$$state, oldState).defaultPrevented;
12337
12338           // if the location was changed by a `$locationChangeStart` handler then stop
12339           // processing this location change
12340           if ($location.absUrl() !== newUrl) return;
12341
12342           if (defaultPrevented) {
12343             $location.$$parse(oldUrl);
12344             $location.$$state = oldState;
12345           } else {
12346             if (urlOrStateChanged) {
12347               setBrowserUrlWithFallback(newUrl, currentReplace,
12348                                         oldState === $location.$$state ? null : $location.$$state);
12349             }
12350             afterLocationChange(oldUrl, oldState);
12351           }
12352         });
12353       }
12354
12355       $location.$$replace = false;
12356
12357       // we don't need to return anything because $evalAsync will make the digest loop dirty when
12358       // there is a change
12359     });
12360
12361     return $location;
12362
12363     function afterLocationChange(oldUrl, oldState) {
12364       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
12365         $location.$$state, oldState);
12366     }
12367 }];
12368 }
12369
12370 /**
12371  * @ngdoc service
12372  * @name $log
12373  * @requires $window
12374  *
12375  * @description
12376  * Simple service for logging. Default implementation safely writes the message
12377  * into the browser's console (if present).
12378  *
12379  * The main purpose of this service is to simplify debugging and troubleshooting.
12380  *
12381  * The default is to log `debug` messages. You can use
12382  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
12383  *
12384  * @example
12385    <example module="logExample">
12386      <file name="script.js">
12387        angular.module('logExample', [])
12388          .controller('LogController', ['$scope', '$log', function($scope, $log) {
12389            $scope.$log = $log;
12390            $scope.message = 'Hello World!';
12391          }]);
12392      </file>
12393      <file name="index.html">
12394        <div ng-controller="LogController">
12395          <p>Reload this page with open console, enter text and hit the log button...</p>
12396          <label>Message:
12397          <input type="text" ng-model="message" /></label>
12398          <button ng-click="$log.log(message)">log</button>
12399          <button ng-click="$log.warn(message)">warn</button>
12400          <button ng-click="$log.info(message)">info</button>
12401          <button ng-click="$log.error(message)">error</button>
12402          <button ng-click="$log.debug(message)">debug</button>
12403        </div>
12404      </file>
12405    </example>
12406  */
12407
12408 /**
12409  * @ngdoc provider
12410  * @name $logProvider
12411  * @description
12412  * Use the `$logProvider` to configure how the application logs messages
12413  */
12414 function $LogProvider() {
12415   var debug = true,
12416       self = this;
12417
12418   /**
12419    * @ngdoc method
12420    * @name $logProvider#debugEnabled
12421    * @description
12422    * @param {boolean=} flag enable or disable debug level messages
12423    * @returns {*} current value if used as getter or itself (chaining) if used as setter
12424    */
12425   this.debugEnabled = function(flag) {
12426     if (isDefined(flag)) {
12427       debug = flag;
12428     return this;
12429     } else {
12430       return debug;
12431     }
12432   };
12433
12434   this.$get = ['$window', function($window) {
12435     return {
12436       /**
12437        * @ngdoc method
12438        * @name $log#log
12439        *
12440        * @description
12441        * Write a log message
12442        */
12443       log: consoleLog('log'),
12444
12445       /**
12446        * @ngdoc method
12447        * @name $log#info
12448        *
12449        * @description
12450        * Write an information message
12451        */
12452       info: consoleLog('info'),
12453
12454       /**
12455        * @ngdoc method
12456        * @name $log#warn
12457        *
12458        * @description
12459        * Write a warning message
12460        */
12461       warn: consoleLog('warn'),
12462
12463       /**
12464        * @ngdoc method
12465        * @name $log#error
12466        *
12467        * @description
12468        * Write an error message
12469        */
12470       error: consoleLog('error'),
12471
12472       /**
12473        * @ngdoc method
12474        * @name $log#debug
12475        *
12476        * @description
12477        * Write a debug message
12478        */
12479       debug: (function() {
12480         var fn = consoleLog('debug');
12481
12482         return function() {
12483           if (debug) {
12484             fn.apply(self, arguments);
12485           }
12486         };
12487       }())
12488     };
12489
12490     function formatError(arg) {
12491       if (arg instanceof Error) {
12492         if (arg.stack) {
12493           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
12494               ? 'Error: ' + arg.message + '\n' + arg.stack
12495               : arg.stack;
12496         } else if (arg.sourceURL) {
12497           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
12498         }
12499       }
12500       return arg;
12501     }
12502
12503     function consoleLog(type) {
12504       var console = $window.console || {},
12505           logFn = console[type] || console.log || noop,
12506           hasApply = false;
12507
12508       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
12509       // The reason behind this is that console.log has type "object" in IE8...
12510       try {
12511         hasApply = !!logFn.apply;
12512       } catch (e) {}
12513
12514       if (hasApply) {
12515         return function() {
12516           var args = [];
12517           forEach(arguments, function(arg) {
12518             args.push(formatError(arg));
12519           });
12520           return logFn.apply(console, args);
12521         };
12522       }
12523
12524       // we are IE which either doesn't have window.console => this is noop and we do nothing,
12525       // or we are IE where console.log doesn't have apply so we log at least first 2 args
12526       return function(arg1, arg2) {
12527         logFn(arg1, arg2 == null ? '' : arg2);
12528       };
12529     }
12530   }];
12531 }
12532
12533 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12534  *     Any commits to this file should be reviewed with security in mind.  *
12535  *   Changes to this file can potentially create security vulnerabilities. *
12536  *          An approval from 2 Core members with history of modifying      *
12537  *                         this file is required.                          *
12538  *                                                                         *
12539  *  Does the change somehow allow for arbitrary javascript to be executed? *
12540  *    Or allows for someone to change the prototype of built-in objects?   *
12541  *     Or gives undesired access to variables likes document or window?    *
12542  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12543
12544 var $parseMinErr = minErr('$parse');
12545
12546 // Sandboxing Angular Expressions
12547 // ------------------------------
12548 // Angular expressions are generally considered safe because these expressions only have direct
12549 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
12550 // obtaining a reference to native JS functions such as the Function constructor.
12551 //
12552 // As an example, consider the following Angular expression:
12553 //
12554 //   {}.toString.constructor('alert("evil JS code")')
12555 //
12556 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
12557 // against the expression language, but not to prevent exploits that were enabled by exposing
12558 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
12559 // practice and therefore we are not even trying to protect against interaction with an object
12560 // explicitly exposed in this way.
12561 //
12562 // In general, it is not possible to access a Window object from an angular expression unless a
12563 // window or some DOM object that has a reference to window is published onto a Scope.
12564 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
12565 // native objects.
12566 //
12567 // See https://docs.angularjs.org/guide/security
12568
12569
12570 function ensureSafeMemberName(name, fullExpression) {
12571   if (name === "__defineGetter__" || name === "__defineSetter__"
12572       || name === "__lookupGetter__" || name === "__lookupSetter__"
12573       || name === "__proto__") {
12574     throw $parseMinErr('isecfld',
12575         'Attempting to access a disallowed field in Angular expressions! '
12576         + 'Expression: {0}', fullExpression);
12577   }
12578   return name;
12579 }
12580
12581 function getStringValue(name, fullExpression) {
12582   // From the JavaScript docs:
12583   // Property names must be strings. This means that non-string objects cannot be used
12584   // as keys in an object. Any non-string object, including a number, is typecasted
12585   // into a string via the toString method.
12586   //
12587   // So, to ensure that we are checking the same `name` that JavaScript would use,
12588   // we cast it to a string, if possible.
12589   // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
12590   // this is, this will handle objects that misbehave.
12591   name = name + '';
12592   if (!isString(name)) {
12593     throw $parseMinErr('iseccst',
12594         'Cannot convert object to primitive value! '
12595         + 'Expression: {0}', fullExpression);
12596   }
12597   return name;
12598 }
12599
12600 function ensureSafeObject(obj, fullExpression) {
12601   // nifty check if obj is Function that is fast and works across iframes and other contexts
12602   if (obj) {
12603     if (obj.constructor === obj) {
12604       throw $parseMinErr('isecfn',
12605           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12606           fullExpression);
12607     } else if (// isWindow(obj)
12608         obj.window === obj) {
12609       throw $parseMinErr('isecwindow',
12610           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
12611           fullExpression);
12612     } else if (// isElement(obj)
12613         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
12614       throw $parseMinErr('isecdom',
12615           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
12616           fullExpression);
12617     } else if (// block Object so that we can't get hold of dangerous Object.* methods
12618         obj === Object) {
12619       throw $parseMinErr('isecobj',
12620           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
12621           fullExpression);
12622     }
12623   }
12624   return obj;
12625 }
12626
12627 var CALL = Function.prototype.call;
12628 var APPLY = Function.prototype.apply;
12629 var BIND = Function.prototype.bind;
12630
12631 function ensureSafeFunction(obj, fullExpression) {
12632   if (obj) {
12633     if (obj.constructor === obj) {
12634       throw $parseMinErr('isecfn',
12635         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12636         fullExpression);
12637     } else if (obj === CALL || obj === APPLY || obj === BIND) {
12638       throw $parseMinErr('isecff',
12639         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
12640         fullExpression);
12641     }
12642   }
12643 }
12644
12645 function ensureSafeAssignContext(obj, fullExpression) {
12646   if (obj) {
12647     if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
12648         obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
12649       throw $parseMinErr('isecaf',
12650         'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
12651     }
12652   }
12653 }
12654
12655 var OPERATORS = createMap();
12656 forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
12657 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
12658
12659
12660 /////////////////////////////////////////
12661
12662
12663 /**
12664  * @constructor
12665  */
12666 var Lexer = function(options) {
12667   this.options = options;
12668 };
12669
12670 Lexer.prototype = {
12671   constructor: Lexer,
12672
12673   lex: function(text) {
12674     this.text = text;
12675     this.index = 0;
12676     this.tokens = [];
12677
12678     while (this.index < this.text.length) {
12679       var ch = this.text.charAt(this.index);
12680       if (ch === '"' || ch === "'") {
12681         this.readString(ch);
12682       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
12683         this.readNumber();
12684       } else if (this.isIdent(ch)) {
12685         this.readIdent();
12686       } else if (this.is(ch, '(){}[].,;:?')) {
12687         this.tokens.push({index: this.index, text: ch});
12688         this.index++;
12689       } else if (this.isWhitespace(ch)) {
12690         this.index++;
12691       } else {
12692         var ch2 = ch + this.peek();
12693         var ch3 = ch2 + this.peek(2);
12694         var op1 = OPERATORS[ch];
12695         var op2 = OPERATORS[ch2];
12696         var op3 = OPERATORS[ch3];
12697         if (op1 || op2 || op3) {
12698           var token = op3 ? ch3 : (op2 ? ch2 : ch);
12699           this.tokens.push({index: this.index, text: token, operator: true});
12700           this.index += token.length;
12701         } else {
12702           this.throwError('Unexpected next character ', this.index, this.index + 1);
12703         }
12704       }
12705     }
12706     return this.tokens;
12707   },
12708
12709   is: function(ch, chars) {
12710     return chars.indexOf(ch) !== -1;
12711   },
12712
12713   peek: function(i) {
12714     var num = i || 1;
12715     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
12716   },
12717
12718   isNumber: function(ch) {
12719     return ('0' <= ch && ch <= '9') && typeof ch === "string";
12720   },
12721
12722   isWhitespace: function(ch) {
12723     // IE treats non-breaking space as \u00A0
12724     return (ch === ' ' || ch === '\r' || ch === '\t' ||
12725             ch === '\n' || ch === '\v' || ch === '\u00A0');
12726   },
12727
12728   isIdent: function(ch) {
12729     return ('a' <= ch && ch <= 'z' ||
12730             'A' <= ch && ch <= 'Z' ||
12731             '_' === ch || ch === '$');
12732   },
12733
12734   isExpOperator: function(ch) {
12735     return (ch === '-' || ch === '+' || this.isNumber(ch));
12736   },
12737
12738   throwError: function(error, start, end) {
12739     end = end || this.index;
12740     var colStr = (isDefined(start)
12741             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
12742             : ' ' + end);
12743     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
12744         error, colStr, this.text);
12745   },
12746
12747   readNumber: function() {
12748     var number = '';
12749     var start = this.index;
12750     while (this.index < this.text.length) {
12751       var ch = lowercase(this.text.charAt(this.index));
12752       if (ch == '.' || this.isNumber(ch)) {
12753         number += ch;
12754       } else {
12755         var peekCh = this.peek();
12756         if (ch == 'e' && this.isExpOperator(peekCh)) {
12757           number += ch;
12758         } else if (this.isExpOperator(ch) &&
12759             peekCh && this.isNumber(peekCh) &&
12760             number.charAt(number.length - 1) == 'e') {
12761           number += ch;
12762         } else if (this.isExpOperator(ch) &&
12763             (!peekCh || !this.isNumber(peekCh)) &&
12764             number.charAt(number.length - 1) == 'e') {
12765           this.throwError('Invalid exponent');
12766         } else {
12767           break;
12768         }
12769       }
12770       this.index++;
12771     }
12772     this.tokens.push({
12773       index: start,
12774       text: number,
12775       constant: true,
12776       value: Number(number)
12777     });
12778   },
12779
12780   readIdent: function() {
12781     var start = this.index;
12782     while (this.index < this.text.length) {
12783       var ch = this.text.charAt(this.index);
12784       if (!(this.isIdent(ch) || this.isNumber(ch))) {
12785         break;
12786       }
12787       this.index++;
12788     }
12789     this.tokens.push({
12790       index: start,
12791       text: this.text.slice(start, this.index),
12792       identifier: true
12793     });
12794   },
12795
12796   readString: function(quote) {
12797     var start = this.index;
12798     this.index++;
12799     var string = '';
12800     var rawString = quote;
12801     var escape = false;
12802     while (this.index < this.text.length) {
12803       var ch = this.text.charAt(this.index);
12804       rawString += ch;
12805       if (escape) {
12806         if (ch === 'u') {
12807           var hex = this.text.substring(this.index + 1, this.index + 5);
12808           if (!hex.match(/[\da-f]{4}/i)) {
12809             this.throwError('Invalid unicode escape [\\u' + hex + ']');
12810           }
12811           this.index += 4;
12812           string += String.fromCharCode(parseInt(hex, 16));
12813         } else {
12814           var rep = ESCAPE[ch];
12815           string = string + (rep || ch);
12816         }
12817         escape = false;
12818       } else if (ch === '\\') {
12819         escape = true;
12820       } else if (ch === quote) {
12821         this.index++;
12822         this.tokens.push({
12823           index: start,
12824           text: rawString,
12825           constant: true,
12826           value: string
12827         });
12828         return;
12829       } else {
12830         string += ch;
12831       }
12832       this.index++;
12833     }
12834     this.throwError('Unterminated quote', start);
12835   }
12836 };
12837
12838 var AST = function(lexer, options) {
12839   this.lexer = lexer;
12840   this.options = options;
12841 };
12842
12843 AST.Program = 'Program';
12844 AST.ExpressionStatement = 'ExpressionStatement';
12845 AST.AssignmentExpression = 'AssignmentExpression';
12846 AST.ConditionalExpression = 'ConditionalExpression';
12847 AST.LogicalExpression = 'LogicalExpression';
12848 AST.BinaryExpression = 'BinaryExpression';
12849 AST.UnaryExpression = 'UnaryExpression';
12850 AST.CallExpression = 'CallExpression';
12851 AST.MemberExpression = 'MemberExpression';
12852 AST.Identifier = 'Identifier';
12853 AST.Literal = 'Literal';
12854 AST.ArrayExpression = 'ArrayExpression';
12855 AST.Property = 'Property';
12856 AST.ObjectExpression = 'ObjectExpression';
12857 AST.ThisExpression = 'ThisExpression';
12858
12859 // Internal use only
12860 AST.NGValueParameter = 'NGValueParameter';
12861
12862 AST.prototype = {
12863   ast: function(text) {
12864     this.text = text;
12865     this.tokens = this.lexer.lex(text);
12866
12867     var value = this.program();
12868
12869     if (this.tokens.length !== 0) {
12870       this.throwError('is an unexpected token', this.tokens[0]);
12871     }
12872
12873     return value;
12874   },
12875
12876   program: function() {
12877     var body = [];
12878     while (true) {
12879       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12880         body.push(this.expressionStatement());
12881       if (!this.expect(';')) {
12882         return { type: AST.Program, body: body};
12883       }
12884     }
12885   },
12886
12887   expressionStatement: function() {
12888     return { type: AST.ExpressionStatement, expression: this.filterChain() };
12889   },
12890
12891   filterChain: function() {
12892     var left = this.expression();
12893     var token;
12894     while ((token = this.expect('|'))) {
12895       left = this.filter(left);
12896     }
12897     return left;
12898   },
12899
12900   expression: function() {
12901     return this.assignment();
12902   },
12903
12904   assignment: function() {
12905     var result = this.ternary();
12906     if (this.expect('=')) {
12907       result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
12908     }
12909     return result;
12910   },
12911
12912   ternary: function() {
12913     var test = this.logicalOR();
12914     var alternate;
12915     var consequent;
12916     if (this.expect('?')) {
12917       alternate = this.expression();
12918       if (this.consume(':')) {
12919         consequent = this.expression();
12920         return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
12921       }
12922     }
12923     return test;
12924   },
12925
12926   logicalOR: function() {
12927     var left = this.logicalAND();
12928     while (this.expect('||')) {
12929       left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
12930     }
12931     return left;
12932   },
12933
12934   logicalAND: function() {
12935     var left = this.equality();
12936     while (this.expect('&&')) {
12937       left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
12938     }
12939     return left;
12940   },
12941
12942   equality: function() {
12943     var left = this.relational();
12944     var token;
12945     while ((token = this.expect('==','!=','===','!=='))) {
12946       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
12947     }
12948     return left;
12949   },
12950
12951   relational: function() {
12952     var left = this.additive();
12953     var token;
12954     while ((token = this.expect('<', '>', '<=', '>='))) {
12955       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
12956     }
12957     return left;
12958   },
12959
12960   additive: function() {
12961     var left = this.multiplicative();
12962     var token;
12963     while ((token = this.expect('+','-'))) {
12964       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
12965     }
12966     return left;
12967   },
12968
12969   multiplicative: function() {
12970     var left = this.unary();
12971     var token;
12972     while ((token = this.expect('*','/','%'))) {
12973       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
12974     }
12975     return left;
12976   },
12977
12978   unary: function() {
12979     var token;
12980     if ((token = this.expect('+', '-', '!'))) {
12981       return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
12982     } else {
12983       return this.primary();
12984     }
12985   },
12986
12987   primary: function() {
12988     var primary;
12989     if (this.expect('(')) {
12990       primary = this.filterChain();
12991       this.consume(')');
12992     } else if (this.expect('[')) {
12993       primary = this.arrayDeclaration();
12994     } else if (this.expect('{')) {
12995       primary = this.object();
12996     } else if (this.constants.hasOwnProperty(this.peek().text)) {
12997       primary = copy(this.constants[this.consume().text]);
12998     } else if (this.peek().identifier) {
12999       primary = this.identifier();
13000     } else if (this.peek().constant) {
13001       primary = this.constant();
13002     } else {
13003       this.throwError('not a primary expression', this.peek());
13004     }
13005
13006     var next;
13007     while ((next = this.expect('(', '[', '.'))) {
13008       if (next.text === '(') {
13009         primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
13010         this.consume(')');
13011       } else if (next.text === '[') {
13012         primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
13013         this.consume(']');
13014       } else if (next.text === '.') {
13015         primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
13016       } else {
13017         this.throwError('IMPOSSIBLE');
13018       }
13019     }
13020     return primary;
13021   },
13022
13023   filter: function(baseExpression) {
13024     var args = [baseExpression];
13025     var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
13026
13027     while (this.expect(':')) {
13028       args.push(this.expression());
13029     }
13030
13031     return result;
13032   },
13033
13034   parseArguments: function() {
13035     var args = [];
13036     if (this.peekToken().text !== ')') {
13037       do {
13038         args.push(this.expression());
13039       } while (this.expect(','));
13040     }
13041     return args;
13042   },
13043
13044   identifier: function() {
13045     var token = this.consume();
13046     if (!token.identifier) {
13047       this.throwError('is not a valid identifier', token);
13048     }
13049     return { type: AST.Identifier, name: token.text };
13050   },
13051
13052   constant: function() {
13053     // TODO check that it is a constant
13054     return { type: AST.Literal, value: this.consume().value };
13055   },
13056
13057   arrayDeclaration: function() {
13058     var elements = [];
13059     if (this.peekToken().text !== ']') {
13060       do {
13061         if (this.peek(']')) {
13062           // Support trailing commas per ES5.1.
13063           break;
13064         }
13065         elements.push(this.expression());
13066       } while (this.expect(','));
13067     }
13068     this.consume(']');
13069
13070     return { type: AST.ArrayExpression, elements: elements };
13071   },
13072
13073   object: function() {
13074     var properties = [], property;
13075     if (this.peekToken().text !== '}') {
13076       do {
13077         if (this.peek('}')) {
13078           // Support trailing commas per ES5.1.
13079           break;
13080         }
13081         property = {type: AST.Property, kind: 'init'};
13082         if (this.peek().constant) {
13083           property.key = this.constant();
13084         } else if (this.peek().identifier) {
13085           property.key = this.identifier();
13086         } else {
13087           this.throwError("invalid key", this.peek());
13088         }
13089         this.consume(':');
13090         property.value = this.expression();
13091         properties.push(property);
13092       } while (this.expect(','));
13093     }
13094     this.consume('}');
13095
13096     return {type: AST.ObjectExpression, properties: properties };
13097   },
13098
13099   throwError: function(msg, token) {
13100     throw $parseMinErr('syntax',
13101         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
13102           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
13103   },
13104
13105   consume: function(e1) {
13106     if (this.tokens.length === 0) {
13107       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13108     }
13109
13110     var token = this.expect(e1);
13111     if (!token) {
13112       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
13113     }
13114     return token;
13115   },
13116
13117   peekToken: function() {
13118     if (this.tokens.length === 0) {
13119       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13120     }
13121     return this.tokens[0];
13122   },
13123
13124   peek: function(e1, e2, e3, e4) {
13125     return this.peekAhead(0, e1, e2, e3, e4);
13126   },
13127
13128   peekAhead: function(i, e1, e2, e3, e4) {
13129     if (this.tokens.length > i) {
13130       var token = this.tokens[i];
13131       var t = token.text;
13132       if (t === e1 || t === e2 || t === e3 || t === e4 ||
13133           (!e1 && !e2 && !e3 && !e4)) {
13134         return token;
13135       }
13136     }
13137     return false;
13138   },
13139
13140   expect: function(e1, e2, e3, e4) {
13141     var token = this.peek(e1, e2, e3, e4);
13142     if (token) {
13143       this.tokens.shift();
13144       return token;
13145     }
13146     return false;
13147   },
13148
13149
13150   /* `undefined` is not a constant, it is an identifier,
13151    * but using it as an identifier is not supported
13152    */
13153   constants: {
13154     'true': { type: AST.Literal, value: true },
13155     'false': { type: AST.Literal, value: false },
13156     'null': { type: AST.Literal, value: null },
13157     'undefined': {type: AST.Literal, value: undefined },
13158     'this': {type: AST.ThisExpression }
13159   }
13160 };
13161
13162 function ifDefined(v, d) {
13163   return typeof v !== 'undefined' ? v : d;
13164 }
13165
13166 function plusFn(l, r) {
13167   if (typeof l === 'undefined') return r;
13168   if (typeof r === 'undefined') return l;
13169   return l + r;
13170 }
13171
13172 function isStateless($filter, filterName) {
13173   var fn = $filter(filterName);
13174   return !fn.$stateful;
13175 }
13176
13177 function findConstantAndWatchExpressions(ast, $filter) {
13178   var allConstants;
13179   var argsToWatch;
13180   switch (ast.type) {
13181   case AST.Program:
13182     allConstants = true;
13183     forEach(ast.body, function(expr) {
13184       findConstantAndWatchExpressions(expr.expression, $filter);
13185       allConstants = allConstants && expr.expression.constant;
13186     });
13187     ast.constant = allConstants;
13188     break;
13189   case AST.Literal:
13190     ast.constant = true;
13191     ast.toWatch = [];
13192     break;
13193   case AST.UnaryExpression:
13194     findConstantAndWatchExpressions(ast.argument, $filter);
13195     ast.constant = ast.argument.constant;
13196     ast.toWatch = ast.argument.toWatch;
13197     break;
13198   case AST.BinaryExpression:
13199     findConstantAndWatchExpressions(ast.left, $filter);
13200     findConstantAndWatchExpressions(ast.right, $filter);
13201     ast.constant = ast.left.constant && ast.right.constant;
13202     ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
13203     break;
13204   case AST.LogicalExpression:
13205     findConstantAndWatchExpressions(ast.left, $filter);
13206     findConstantAndWatchExpressions(ast.right, $filter);
13207     ast.constant = ast.left.constant && ast.right.constant;
13208     ast.toWatch = ast.constant ? [] : [ast];
13209     break;
13210   case AST.ConditionalExpression:
13211     findConstantAndWatchExpressions(ast.test, $filter);
13212     findConstantAndWatchExpressions(ast.alternate, $filter);
13213     findConstantAndWatchExpressions(ast.consequent, $filter);
13214     ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
13215     ast.toWatch = ast.constant ? [] : [ast];
13216     break;
13217   case AST.Identifier:
13218     ast.constant = false;
13219     ast.toWatch = [ast];
13220     break;
13221   case AST.MemberExpression:
13222     findConstantAndWatchExpressions(ast.object, $filter);
13223     if (ast.computed) {
13224       findConstantAndWatchExpressions(ast.property, $filter);
13225     }
13226     ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
13227     ast.toWatch = [ast];
13228     break;
13229   case AST.CallExpression:
13230     allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
13231     argsToWatch = [];
13232     forEach(ast.arguments, function(expr) {
13233       findConstantAndWatchExpressions(expr, $filter);
13234       allConstants = allConstants && expr.constant;
13235       if (!expr.constant) {
13236         argsToWatch.push.apply(argsToWatch, expr.toWatch);
13237       }
13238     });
13239     ast.constant = allConstants;
13240     ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
13241     break;
13242   case AST.AssignmentExpression:
13243     findConstantAndWatchExpressions(ast.left, $filter);
13244     findConstantAndWatchExpressions(ast.right, $filter);
13245     ast.constant = ast.left.constant && ast.right.constant;
13246     ast.toWatch = [ast];
13247     break;
13248   case AST.ArrayExpression:
13249     allConstants = true;
13250     argsToWatch = [];
13251     forEach(ast.elements, function(expr) {
13252       findConstantAndWatchExpressions(expr, $filter);
13253       allConstants = allConstants && expr.constant;
13254       if (!expr.constant) {
13255         argsToWatch.push.apply(argsToWatch, expr.toWatch);
13256       }
13257     });
13258     ast.constant = allConstants;
13259     ast.toWatch = argsToWatch;
13260     break;
13261   case AST.ObjectExpression:
13262     allConstants = true;
13263     argsToWatch = [];
13264     forEach(ast.properties, function(property) {
13265       findConstantAndWatchExpressions(property.value, $filter);
13266       allConstants = allConstants && property.value.constant;
13267       if (!property.value.constant) {
13268         argsToWatch.push.apply(argsToWatch, property.value.toWatch);
13269       }
13270     });
13271     ast.constant = allConstants;
13272     ast.toWatch = argsToWatch;
13273     break;
13274   case AST.ThisExpression:
13275     ast.constant = false;
13276     ast.toWatch = [];
13277     break;
13278   }
13279 }
13280
13281 function getInputs(body) {
13282   if (body.length != 1) return;
13283   var lastExpression = body[0].expression;
13284   var candidate = lastExpression.toWatch;
13285   if (candidate.length !== 1) return candidate;
13286   return candidate[0] !== lastExpression ? candidate : undefined;
13287 }
13288
13289 function isAssignable(ast) {
13290   return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
13291 }
13292
13293 function assignableAST(ast) {
13294   if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
13295     return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
13296   }
13297 }
13298
13299 function isLiteral(ast) {
13300   return ast.body.length === 0 ||
13301       ast.body.length === 1 && (
13302       ast.body[0].expression.type === AST.Literal ||
13303       ast.body[0].expression.type === AST.ArrayExpression ||
13304       ast.body[0].expression.type === AST.ObjectExpression);
13305 }
13306
13307 function isConstant(ast) {
13308   return ast.constant;
13309 }
13310
13311 function ASTCompiler(astBuilder, $filter) {
13312   this.astBuilder = astBuilder;
13313   this.$filter = $filter;
13314 }
13315
13316 ASTCompiler.prototype = {
13317   compile: function(expression, expensiveChecks) {
13318     var self = this;
13319     var ast = this.astBuilder.ast(expression);
13320     this.state = {
13321       nextId: 0,
13322       filters: {},
13323       expensiveChecks: expensiveChecks,
13324       fn: {vars: [], body: [], own: {}},
13325       assign: {vars: [], body: [], own: {}},
13326       inputs: []
13327     };
13328     findConstantAndWatchExpressions(ast, self.$filter);
13329     var extra = '';
13330     var assignable;
13331     this.stage = 'assign';
13332     if ((assignable = assignableAST(ast))) {
13333       this.state.computing = 'assign';
13334       var result = this.nextId();
13335       this.recurse(assignable, result);
13336       this.return_(result);
13337       extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
13338     }
13339     var toWatch = getInputs(ast.body);
13340     self.stage = 'inputs';
13341     forEach(toWatch, function(watch, key) {
13342       var fnKey = 'fn' + key;
13343       self.state[fnKey] = {vars: [], body: [], own: {}};
13344       self.state.computing = fnKey;
13345       var intoId = self.nextId();
13346       self.recurse(watch, intoId);
13347       self.return_(intoId);
13348       self.state.inputs.push(fnKey);
13349       watch.watchId = key;
13350     });
13351     this.state.computing = 'fn';
13352     this.stage = 'main';
13353     this.recurse(ast);
13354     var fnString =
13355       // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
13356       // This is a workaround for this until we do a better job at only removing the prefix only when we should.
13357       '"' + this.USE + ' ' + this.STRICT + '";\n' +
13358       this.filterPrefix() +
13359       'var fn=' + this.generateFunction('fn', 's,l,a,i') +
13360       extra +
13361       this.watchFns() +
13362       'return fn;';
13363
13364     /* jshint -W054 */
13365     var fn = (new Function('$filter',
13366         'ensureSafeMemberName',
13367         'ensureSafeObject',
13368         'ensureSafeFunction',
13369         'getStringValue',
13370         'ensureSafeAssignContext',
13371         'ifDefined',
13372         'plus',
13373         'text',
13374         fnString))(
13375           this.$filter,
13376           ensureSafeMemberName,
13377           ensureSafeObject,
13378           ensureSafeFunction,
13379           getStringValue,
13380           ensureSafeAssignContext,
13381           ifDefined,
13382           plusFn,
13383           expression);
13384     /* jshint +W054 */
13385     this.state = this.stage = undefined;
13386     fn.literal = isLiteral(ast);
13387     fn.constant = isConstant(ast);
13388     return fn;
13389   },
13390
13391   USE: 'use',
13392
13393   STRICT: 'strict',
13394
13395   watchFns: function() {
13396     var result = [];
13397     var fns = this.state.inputs;
13398     var self = this;
13399     forEach(fns, function(name) {
13400       result.push('var ' + name + '=' + self.generateFunction(name, 's'));
13401     });
13402     if (fns.length) {
13403       result.push('fn.inputs=[' + fns.join(',') + '];');
13404     }
13405     return result.join('');
13406   },
13407
13408   generateFunction: function(name, params) {
13409     return 'function(' + params + '){' +
13410         this.varsPrefix(name) +
13411         this.body(name) +
13412         '};';
13413   },
13414
13415   filterPrefix: function() {
13416     var parts = [];
13417     var self = this;
13418     forEach(this.state.filters, function(id, filter) {
13419       parts.push(id + '=$filter(' + self.escape(filter) + ')');
13420     });
13421     if (parts.length) return 'var ' + parts.join(',') + ';';
13422     return '';
13423   },
13424
13425   varsPrefix: function(section) {
13426     return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
13427   },
13428
13429   body: function(section) {
13430     return this.state[section].body.join('');
13431   },
13432
13433   recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13434     var left, right, self = this, args, expression;
13435     recursionFn = recursionFn || noop;
13436     if (!skipWatchIdCheck && isDefined(ast.watchId)) {
13437       intoId = intoId || this.nextId();
13438       this.if_('i',
13439         this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
13440         this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
13441       );
13442       return;
13443     }
13444     switch (ast.type) {
13445     case AST.Program:
13446       forEach(ast.body, function(expression, pos) {
13447         self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
13448         if (pos !== ast.body.length - 1) {
13449           self.current().body.push(right, ';');
13450         } else {
13451           self.return_(right);
13452         }
13453       });
13454       break;
13455     case AST.Literal:
13456       expression = this.escape(ast.value);
13457       this.assign(intoId, expression);
13458       recursionFn(expression);
13459       break;
13460     case AST.UnaryExpression:
13461       this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
13462       expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
13463       this.assign(intoId, expression);
13464       recursionFn(expression);
13465       break;
13466     case AST.BinaryExpression:
13467       this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
13468       this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
13469       if (ast.operator === '+') {
13470         expression = this.plus(left, right);
13471       } else if (ast.operator === '-') {
13472         expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
13473       } else {
13474         expression = '(' + left + ')' + ast.operator + '(' + right + ')';
13475       }
13476       this.assign(intoId, expression);
13477       recursionFn(expression);
13478       break;
13479     case AST.LogicalExpression:
13480       intoId = intoId || this.nextId();
13481       self.recurse(ast.left, intoId);
13482       self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
13483       recursionFn(intoId);
13484       break;
13485     case AST.ConditionalExpression:
13486       intoId = intoId || this.nextId();
13487       self.recurse(ast.test, intoId);
13488       self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
13489       recursionFn(intoId);
13490       break;
13491     case AST.Identifier:
13492       intoId = intoId || this.nextId();
13493       if (nameId) {
13494         nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
13495         nameId.computed = false;
13496         nameId.name = ast.name;
13497       }
13498       ensureSafeMemberName(ast.name);
13499       self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
13500         function() {
13501           self.if_(self.stage === 'inputs' || 's', function() {
13502             if (create && create !== 1) {
13503               self.if_(
13504                 self.not(self.nonComputedMember('s', ast.name)),
13505                 self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
13506             }
13507             self.assign(intoId, self.nonComputedMember('s', ast.name));
13508           });
13509         }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
13510         );
13511       if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
13512         self.addEnsureSafeObject(intoId);
13513       }
13514       recursionFn(intoId);
13515       break;
13516     case AST.MemberExpression:
13517       left = nameId && (nameId.context = this.nextId()) || this.nextId();
13518       intoId = intoId || this.nextId();
13519       self.recurse(ast.object, left, undefined, function() {
13520         self.if_(self.notNull(left), function() {
13521           if (ast.computed) {
13522             right = self.nextId();
13523             self.recurse(ast.property, right);
13524             self.getStringValue(right);
13525             self.addEnsureSafeMemberName(right);
13526             if (create && create !== 1) {
13527               self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
13528             }
13529             expression = self.ensureSafeObject(self.computedMember(left, right));
13530             self.assign(intoId, expression);
13531             if (nameId) {
13532               nameId.computed = true;
13533               nameId.name = right;
13534             }
13535           } else {
13536             ensureSafeMemberName(ast.property.name);
13537             if (create && create !== 1) {
13538               self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
13539             }
13540             expression = self.nonComputedMember(left, ast.property.name);
13541             if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
13542               expression = self.ensureSafeObject(expression);
13543             }
13544             self.assign(intoId, expression);
13545             if (nameId) {
13546               nameId.computed = false;
13547               nameId.name = ast.property.name;
13548             }
13549           }
13550         }, function() {
13551           self.assign(intoId, 'undefined');
13552         });
13553         recursionFn(intoId);
13554       }, !!create);
13555       break;
13556     case AST.CallExpression:
13557       intoId = intoId || this.nextId();
13558       if (ast.filter) {
13559         right = self.filter(ast.callee.name);
13560         args = [];
13561         forEach(ast.arguments, function(expr) {
13562           var argument = self.nextId();
13563           self.recurse(expr, argument);
13564           args.push(argument);
13565         });
13566         expression = right + '(' + args.join(',') + ')';
13567         self.assign(intoId, expression);
13568         recursionFn(intoId);
13569       } else {
13570         right = self.nextId();
13571         left = {};
13572         args = [];
13573         self.recurse(ast.callee, right, left, function() {
13574           self.if_(self.notNull(right), function() {
13575             self.addEnsureSafeFunction(right);
13576             forEach(ast.arguments, function(expr) {
13577               self.recurse(expr, self.nextId(), undefined, function(argument) {
13578                 args.push(self.ensureSafeObject(argument));
13579               });
13580             });
13581             if (left.name) {
13582               if (!self.state.expensiveChecks) {
13583                 self.addEnsureSafeObject(left.context);
13584               }
13585               expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
13586             } else {
13587               expression = right + '(' + args.join(',') + ')';
13588             }
13589             expression = self.ensureSafeObject(expression);
13590             self.assign(intoId, expression);
13591           }, function() {
13592             self.assign(intoId, 'undefined');
13593           });
13594           recursionFn(intoId);
13595         });
13596       }
13597       break;
13598     case AST.AssignmentExpression:
13599       right = this.nextId();
13600       left = {};
13601       if (!isAssignable(ast.left)) {
13602         throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
13603       }
13604       this.recurse(ast.left, undefined, left, function() {
13605         self.if_(self.notNull(left.context), function() {
13606           self.recurse(ast.right, right);
13607           self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
13608           self.addEnsureSafeAssignContext(left.context);
13609           expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
13610           self.assign(intoId, expression);
13611           recursionFn(intoId || expression);
13612         });
13613       }, 1);
13614       break;
13615     case AST.ArrayExpression:
13616       args = [];
13617       forEach(ast.elements, function(expr) {
13618         self.recurse(expr, self.nextId(), undefined, function(argument) {
13619           args.push(argument);
13620         });
13621       });
13622       expression = '[' + args.join(',') + ']';
13623       this.assign(intoId, expression);
13624       recursionFn(expression);
13625       break;
13626     case AST.ObjectExpression:
13627       args = [];
13628       forEach(ast.properties, function(property) {
13629         self.recurse(property.value, self.nextId(), undefined, function(expr) {
13630           args.push(self.escape(
13631               property.key.type === AST.Identifier ? property.key.name :
13632                 ('' + property.key.value)) +
13633               ':' + expr);
13634         });
13635       });
13636       expression = '{' + args.join(',') + '}';
13637       this.assign(intoId, expression);
13638       recursionFn(expression);
13639       break;
13640     case AST.ThisExpression:
13641       this.assign(intoId, 's');
13642       recursionFn('s');
13643       break;
13644     case AST.NGValueParameter:
13645       this.assign(intoId, 'v');
13646       recursionFn('v');
13647       break;
13648     }
13649   },
13650
13651   getHasOwnProperty: function(element, property) {
13652     var key = element + '.' + property;
13653     var own = this.current().own;
13654     if (!own.hasOwnProperty(key)) {
13655       own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
13656     }
13657     return own[key];
13658   },
13659
13660   assign: function(id, value) {
13661     if (!id) return;
13662     this.current().body.push(id, '=', value, ';');
13663     return id;
13664   },
13665
13666   filter: function(filterName) {
13667     if (!this.state.filters.hasOwnProperty(filterName)) {
13668       this.state.filters[filterName] = this.nextId(true);
13669     }
13670     return this.state.filters[filterName];
13671   },
13672
13673   ifDefined: function(id, defaultValue) {
13674     return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
13675   },
13676
13677   plus: function(left, right) {
13678     return 'plus(' + left + ',' + right + ')';
13679   },
13680
13681   return_: function(id) {
13682     this.current().body.push('return ', id, ';');
13683   },
13684
13685   if_: function(test, alternate, consequent) {
13686     if (test === true) {
13687       alternate();
13688     } else {
13689       var body = this.current().body;
13690       body.push('if(', test, '){');
13691       alternate();
13692       body.push('}');
13693       if (consequent) {
13694         body.push('else{');
13695         consequent();
13696         body.push('}');
13697       }
13698     }
13699   },
13700
13701   not: function(expression) {
13702     return '!(' + expression + ')';
13703   },
13704
13705   notNull: function(expression) {
13706     return expression + '!=null';
13707   },
13708
13709   nonComputedMember: function(left, right) {
13710     return left + '.' + right;
13711   },
13712
13713   computedMember: function(left, right) {
13714     return left + '[' + right + ']';
13715   },
13716
13717   member: function(left, right, computed) {
13718     if (computed) return this.computedMember(left, right);
13719     return this.nonComputedMember(left, right);
13720   },
13721
13722   addEnsureSafeObject: function(item) {
13723     this.current().body.push(this.ensureSafeObject(item), ';');
13724   },
13725
13726   addEnsureSafeMemberName: function(item) {
13727     this.current().body.push(this.ensureSafeMemberName(item), ';');
13728   },
13729
13730   addEnsureSafeFunction: function(item) {
13731     this.current().body.push(this.ensureSafeFunction(item), ';');
13732   },
13733
13734   addEnsureSafeAssignContext: function(item) {
13735     this.current().body.push(this.ensureSafeAssignContext(item), ';');
13736   },
13737
13738   ensureSafeObject: function(item) {
13739     return 'ensureSafeObject(' + item + ',text)';
13740   },
13741
13742   ensureSafeMemberName: function(item) {
13743     return 'ensureSafeMemberName(' + item + ',text)';
13744   },
13745
13746   ensureSafeFunction: function(item) {
13747     return 'ensureSafeFunction(' + item + ',text)';
13748   },
13749
13750   getStringValue: function(item) {
13751     this.assign(item, 'getStringValue(' + item + ',text)');
13752   },
13753
13754   ensureSafeAssignContext: function(item) {
13755     return 'ensureSafeAssignContext(' + item + ',text)';
13756   },
13757
13758   lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13759     var self = this;
13760     return function() {
13761       self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
13762     };
13763   },
13764
13765   lazyAssign: function(id, value) {
13766     var self = this;
13767     return function() {
13768       self.assign(id, value);
13769     };
13770   },
13771
13772   stringEscapeRegex: /[^ a-zA-Z0-9]/g,
13773
13774   stringEscapeFn: function(c) {
13775     return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
13776   },
13777
13778   escape: function(value) {
13779     if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
13780     if (isNumber(value)) return value.toString();
13781     if (value === true) return 'true';
13782     if (value === false) return 'false';
13783     if (value === null) return 'null';
13784     if (typeof value === 'undefined') return 'undefined';
13785
13786     throw $parseMinErr('esc', 'IMPOSSIBLE');
13787   },
13788
13789   nextId: function(skip, init) {
13790     var id = 'v' + (this.state.nextId++);
13791     if (!skip) {
13792       this.current().vars.push(id + (init ? '=' + init : ''));
13793     }
13794     return id;
13795   },
13796
13797   current: function() {
13798     return this.state[this.state.computing];
13799   }
13800 };
13801
13802
13803 function ASTInterpreter(astBuilder, $filter) {
13804   this.astBuilder = astBuilder;
13805   this.$filter = $filter;
13806 }
13807
13808 ASTInterpreter.prototype = {
13809   compile: function(expression, expensiveChecks) {
13810     var self = this;
13811     var ast = this.astBuilder.ast(expression);
13812     this.expression = expression;
13813     this.expensiveChecks = expensiveChecks;
13814     findConstantAndWatchExpressions(ast, self.$filter);
13815     var assignable;
13816     var assign;
13817     if ((assignable = assignableAST(ast))) {
13818       assign = this.recurse(assignable);
13819     }
13820     var toWatch = getInputs(ast.body);
13821     var inputs;
13822     if (toWatch) {
13823       inputs = [];
13824       forEach(toWatch, function(watch, key) {
13825         var input = self.recurse(watch);
13826         watch.input = input;
13827         inputs.push(input);
13828         watch.watchId = key;
13829       });
13830     }
13831     var expressions = [];
13832     forEach(ast.body, function(expression) {
13833       expressions.push(self.recurse(expression.expression));
13834     });
13835     var fn = ast.body.length === 0 ? function() {} :
13836              ast.body.length === 1 ? expressions[0] :
13837              function(scope, locals) {
13838                var lastValue;
13839                forEach(expressions, function(exp) {
13840                  lastValue = exp(scope, locals);
13841                });
13842                return lastValue;
13843              };
13844     if (assign) {
13845       fn.assign = function(scope, value, locals) {
13846         return assign(scope, locals, value);
13847       };
13848     }
13849     if (inputs) {
13850       fn.inputs = inputs;
13851     }
13852     fn.literal = isLiteral(ast);
13853     fn.constant = isConstant(ast);
13854     return fn;
13855   },
13856
13857   recurse: function(ast, context, create) {
13858     var left, right, self = this, args, expression;
13859     if (ast.input) {
13860       return this.inputs(ast.input, ast.watchId);
13861     }
13862     switch (ast.type) {
13863     case AST.Literal:
13864       return this.value(ast.value, context);
13865     case AST.UnaryExpression:
13866       right = this.recurse(ast.argument);
13867       return this['unary' + ast.operator](right, context);
13868     case AST.BinaryExpression:
13869       left = this.recurse(ast.left);
13870       right = this.recurse(ast.right);
13871       return this['binary' + ast.operator](left, right, context);
13872     case AST.LogicalExpression:
13873       left = this.recurse(ast.left);
13874       right = this.recurse(ast.right);
13875       return this['binary' + ast.operator](left, right, context);
13876     case AST.ConditionalExpression:
13877       return this['ternary?:'](
13878         this.recurse(ast.test),
13879         this.recurse(ast.alternate),
13880         this.recurse(ast.consequent),
13881         context
13882       );
13883     case AST.Identifier:
13884       ensureSafeMemberName(ast.name, self.expression);
13885       return self.identifier(ast.name,
13886                              self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
13887                              context, create, self.expression);
13888     case AST.MemberExpression:
13889       left = this.recurse(ast.object, false, !!create);
13890       if (!ast.computed) {
13891         ensureSafeMemberName(ast.property.name, self.expression);
13892         right = ast.property.name;
13893       }
13894       if (ast.computed) right = this.recurse(ast.property);
13895       return ast.computed ?
13896         this.computedMember(left, right, context, create, self.expression) :
13897         this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
13898     case AST.CallExpression:
13899       args = [];
13900       forEach(ast.arguments, function(expr) {
13901         args.push(self.recurse(expr));
13902       });
13903       if (ast.filter) right = this.$filter(ast.callee.name);
13904       if (!ast.filter) right = this.recurse(ast.callee, true);
13905       return ast.filter ?
13906         function(scope, locals, assign, inputs) {
13907           var values = [];
13908           for (var i = 0; i < args.length; ++i) {
13909             values.push(args[i](scope, locals, assign, inputs));
13910           }
13911           var value = right.apply(undefined, values, inputs);
13912           return context ? {context: undefined, name: undefined, value: value} : value;
13913         } :
13914         function(scope, locals, assign, inputs) {
13915           var rhs = right(scope, locals, assign, inputs);
13916           var value;
13917           if (rhs.value != null) {
13918             ensureSafeObject(rhs.context, self.expression);
13919             ensureSafeFunction(rhs.value, self.expression);
13920             var values = [];
13921             for (var i = 0; i < args.length; ++i) {
13922               values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
13923             }
13924             value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
13925           }
13926           return context ? {value: value} : value;
13927         };
13928     case AST.AssignmentExpression:
13929       left = this.recurse(ast.left, true, 1);
13930       right = this.recurse(ast.right);
13931       return function(scope, locals, assign, inputs) {
13932         var lhs = left(scope, locals, assign, inputs);
13933         var rhs = right(scope, locals, assign, inputs);
13934         ensureSafeObject(lhs.value, self.expression);
13935         ensureSafeAssignContext(lhs.context);
13936         lhs.context[lhs.name] = rhs;
13937         return context ? {value: rhs} : rhs;
13938       };
13939     case AST.ArrayExpression:
13940       args = [];
13941       forEach(ast.elements, function(expr) {
13942         args.push(self.recurse(expr));
13943       });
13944       return function(scope, locals, assign, inputs) {
13945         var value = [];
13946         for (var i = 0; i < args.length; ++i) {
13947           value.push(args[i](scope, locals, assign, inputs));
13948         }
13949         return context ? {value: value} : value;
13950       };
13951     case AST.ObjectExpression:
13952       args = [];
13953       forEach(ast.properties, function(property) {
13954         args.push({key: property.key.type === AST.Identifier ?
13955                         property.key.name :
13956                         ('' + property.key.value),
13957                    value: self.recurse(property.value)
13958         });
13959       });
13960       return function(scope, locals, assign, inputs) {
13961         var value = {};
13962         for (var i = 0; i < args.length; ++i) {
13963           value[args[i].key] = args[i].value(scope, locals, assign, inputs);
13964         }
13965         return context ? {value: value} : value;
13966       };
13967     case AST.ThisExpression:
13968       return function(scope) {
13969         return context ? {value: scope} : scope;
13970       };
13971     case AST.NGValueParameter:
13972       return function(scope, locals, assign, inputs) {
13973         return context ? {value: assign} : assign;
13974       };
13975     }
13976   },
13977
13978   'unary+': function(argument, context) {
13979     return function(scope, locals, assign, inputs) {
13980       var arg = argument(scope, locals, assign, inputs);
13981       if (isDefined(arg)) {
13982         arg = +arg;
13983       } else {
13984         arg = 0;
13985       }
13986       return context ? {value: arg} : arg;
13987     };
13988   },
13989   'unary-': function(argument, context) {
13990     return function(scope, locals, assign, inputs) {
13991       var arg = argument(scope, locals, assign, inputs);
13992       if (isDefined(arg)) {
13993         arg = -arg;
13994       } else {
13995         arg = 0;
13996       }
13997       return context ? {value: arg} : arg;
13998     };
13999   },
14000   'unary!': function(argument, context) {
14001     return function(scope, locals, assign, inputs) {
14002       var arg = !argument(scope, locals, assign, inputs);
14003       return context ? {value: arg} : arg;
14004     };
14005   },
14006   'binary+': function(left, right, context) {
14007     return function(scope, locals, assign, inputs) {
14008       var lhs = left(scope, locals, assign, inputs);
14009       var rhs = right(scope, locals, assign, inputs);
14010       var arg = plusFn(lhs, rhs);
14011       return context ? {value: arg} : arg;
14012     };
14013   },
14014   'binary-': function(left, right, context) {
14015     return function(scope, locals, assign, inputs) {
14016       var lhs = left(scope, locals, assign, inputs);
14017       var rhs = right(scope, locals, assign, inputs);
14018       var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
14019       return context ? {value: arg} : arg;
14020     };
14021   },
14022   'binary*': function(left, right, context) {
14023     return function(scope, locals, assign, inputs) {
14024       var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
14025       return context ? {value: arg} : arg;
14026     };
14027   },
14028   'binary/': function(left, right, context) {
14029     return function(scope, locals, assign, inputs) {
14030       var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
14031       return context ? {value: arg} : arg;
14032     };
14033   },
14034   'binary%': function(left, right, context) {
14035     return function(scope, locals, assign, inputs) {
14036       var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
14037       return context ? {value: arg} : arg;
14038     };
14039   },
14040   'binary===': function(left, right, context) {
14041     return function(scope, locals, assign, inputs) {
14042       var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
14043       return context ? {value: arg} : arg;
14044     };
14045   },
14046   'binary!==': function(left, right, context) {
14047     return function(scope, locals, assign, inputs) {
14048       var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
14049       return context ? {value: arg} : arg;
14050     };
14051   },
14052   'binary==': function(left, right, context) {
14053     return function(scope, locals, assign, inputs) {
14054       var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
14055       return context ? {value: arg} : arg;
14056     };
14057   },
14058   'binary!=': function(left, right, context) {
14059     return function(scope, locals, assign, inputs) {
14060       var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
14061       return context ? {value: arg} : arg;
14062     };
14063   },
14064   'binary<': function(left, right, context) {
14065     return function(scope, locals, assign, inputs) {
14066       var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
14067       return context ? {value: arg} : arg;
14068     };
14069   },
14070   'binary>': function(left, right, context) {
14071     return function(scope, locals, assign, inputs) {
14072       var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
14073       return context ? {value: arg} : arg;
14074     };
14075   },
14076   'binary<=': function(left, right, context) {
14077     return function(scope, locals, assign, inputs) {
14078       var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
14079       return context ? {value: arg} : arg;
14080     };
14081   },
14082   'binary>=': function(left, right, context) {
14083     return function(scope, locals, assign, inputs) {
14084       var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
14085       return context ? {value: arg} : arg;
14086     };
14087   },
14088   'binary&&': function(left, right, context) {
14089     return function(scope, locals, assign, inputs) {
14090       var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
14091       return context ? {value: arg} : arg;
14092     };
14093   },
14094   'binary||': function(left, right, context) {
14095     return function(scope, locals, assign, inputs) {
14096       var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
14097       return context ? {value: arg} : arg;
14098     };
14099   },
14100   'ternary?:': function(test, alternate, consequent, context) {
14101     return function(scope, locals, assign, inputs) {
14102       var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
14103       return context ? {value: arg} : arg;
14104     };
14105   },
14106   value: function(value, context) {
14107     return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
14108   },
14109   identifier: function(name, expensiveChecks, context, create, expression) {
14110     return function(scope, locals, assign, inputs) {
14111       var base = locals && (name in locals) ? locals : scope;
14112       if (create && create !== 1 && base && !(base[name])) {
14113         base[name] = {};
14114       }
14115       var value = base ? base[name] : undefined;
14116       if (expensiveChecks) {
14117         ensureSafeObject(value, expression);
14118       }
14119       if (context) {
14120         return {context: base, name: name, value: value};
14121       } else {
14122         return value;
14123       }
14124     };
14125   },
14126   computedMember: function(left, right, context, create, expression) {
14127     return function(scope, locals, assign, inputs) {
14128       var lhs = left(scope, locals, assign, inputs);
14129       var rhs;
14130       var value;
14131       if (lhs != null) {
14132         rhs = right(scope, locals, assign, inputs);
14133         rhs = getStringValue(rhs);
14134         ensureSafeMemberName(rhs, expression);
14135         if (create && create !== 1 && lhs && !(lhs[rhs])) {
14136           lhs[rhs] = {};
14137         }
14138         value = lhs[rhs];
14139         ensureSafeObject(value, expression);
14140       }
14141       if (context) {
14142         return {context: lhs, name: rhs, value: value};
14143       } else {
14144         return value;
14145       }
14146     };
14147   },
14148   nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
14149     return function(scope, locals, assign, inputs) {
14150       var lhs = left(scope, locals, assign, inputs);
14151       if (create && create !== 1 && lhs && !(lhs[right])) {
14152         lhs[right] = {};
14153       }
14154       var value = lhs != null ? lhs[right] : undefined;
14155       if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
14156         ensureSafeObject(value, expression);
14157       }
14158       if (context) {
14159         return {context: lhs, name: right, value: value};
14160       } else {
14161         return value;
14162       }
14163     };
14164   },
14165   inputs: function(input, watchId) {
14166     return function(scope, value, locals, inputs) {
14167       if (inputs) return inputs[watchId];
14168       return input(scope, value, locals);
14169     };
14170   }
14171 };
14172
14173 /**
14174  * @constructor
14175  */
14176 var Parser = function(lexer, $filter, options) {
14177   this.lexer = lexer;
14178   this.$filter = $filter;
14179   this.options = options;
14180   this.ast = new AST(this.lexer);
14181   this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
14182                                    new ASTCompiler(this.ast, $filter);
14183 };
14184
14185 Parser.prototype = {
14186   constructor: Parser,
14187
14188   parse: function(text) {
14189     return this.astCompiler.compile(text, this.options.expensiveChecks);
14190   }
14191 };
14192
14193 var getterFnCacheDefault = createMap();
14194 var getterFnCacheExpensive = createMap();
14195
14196 function isPossiblyDangerousMemberName(name) {
14197   return name == 'constructor';
14198 }
14199
14200 var objectValueOf = Object.prototype.valueOf;
14201
14202 function getValueOf(value) {
14203   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
14204 }
14205
14206 ///////////////////////////////////
14207
14208 /**
14209  * @ngdoc service
14210  * @name $parse
14211  * @kind function
14212  *
14213  * @description
14214  *
14215  * Converts Angular {@link guide/expression expression} into a function.
14216  *
14217  * ```js
14218  *   var getter = $parse('user.name');
14219  *   var setter = getter.assign;
14220  *   var context = {user:{name:'angular'}};
14221  *   var locals = {user:{name:'local'}};
14222  *
14223  *   expect(getter(context)).toEqual('angular');
14224  *   setter(context, 'newValue');
14225  *   expect(context.user.name).toEqual('newValue');
14226  *   expect(getter(context, locals)).toEqual('local');
14227  * ```
14228  *
14229  *
14230  * @param {string} expression String expression to compile.
14231  * @returns {function(context, locals)} a function which represents the compiled expression:
14232  *
14233  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14234  *      are evaluated against (typically a scope object).
14235  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14236  *      `context`.
14237  *
14238  *    The returned function also has the following properties:
14239  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
14240  *        literal.
14241  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
14242  *        constant literals.
14243  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
14244  *        set to a function to change its value on the given context.
14245  *
14246  */
14247
14248
14249 /**
14250  * @ngdoc provider
14251  * @name $parseProvider
14252  *
14253  * @description
14254  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
14255  *  service.
14256  */
14257 function $ParseProvider() {
14258   var cacheDefault = createMap();
14259   var cacheExpensive = createMap();
14260
14261   this.$get = ['$filter', function($filter) {
14262     var noUnsafeEval = csp().noUnsafeEval;
14263     var $parseOptions = {
14264           csp: noUnsafeEval,
14265           expensiveChecks: false
14266         },
14267         $parseOptionsExpensive = {
14268           csp: noUnsafeEval,
14269           expensiveChecks: true
14270         };
14271
14272     return function $parse(exp, interceptorFn, expensiveChecks) {
14273       var parsedExpression, oneTime, cacheKey;
14274
14275       switch (typeof exp) {
14276         case 'string':
14277           exp = exp.trim();
14278           cacheKey = exp;
14279
14280           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
14281           parsedExpression = cache[cacheKey];
14282
14283           if (!parsedExpression) {
14284             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
14285               oneTime = true;
14286               exp = exp.substring(2);
14287             }
14288             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
14289             var lexer = new Lexer(parseOptions);
14290             var parser = new Parser(lexer, $filter, parseOptions);
14291             parsedExpression = parser.parse(exp);
14292             if (parsedExpression.constant) {
14293               parsedExpression.$$watchDelegate = constantWatchDelegate;
14294             } else if (oneTime) {
14295               parsedExpression.$$watchDelegate = parsedExpression.literal ?
14296                   oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
14297             } else if (parsedExpression.inputs) {
14298               parsedExpression.$$watchDelegate = inputsWatchDelegate;
14299             }
14300             cache[cacheKey] = parsedExpression;
14301           }
14302           return addInterceptor(parsedExpression, interceptorFn);
14303
14304         case 'function':
14305           return addInterceptor(exp, interceptorFn);
14306
14307         default:
14308           return noop;
14309       }
14310     };
14311
14312     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
14313
14314       if (newValue == null || oldValueOfValue == null) { // null/undefined
14315         return newValue === oldValueOfValue;
14316       }
14317
14318       if (typeof newValue === 'object') {
14319
14320         // attempt to convert the value to a primitive type
14321         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
14322         //             be cheaply dirty-checked
14323         newValue = getValueOf(newValue);
14324
14325         if (typeof newValue === 'object') {
14326           // objects/arrays are not supported - deep-watching them would be too expensive
14327           return false;
14328         }
14329
14330         // fall-through to the primitive equality check
14331       }
14332
14333       //Primitive or NaN
14334       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
14335     }
14336
14337     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
14338       var inputExpressions = parsedExpression.inputs;
14339       var lastResult;
14340
14341       if (inputExpressions.length === 1) {
14342         var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
14343         inputExpressions = inputExpressions[0];
14344         return scope.$watch(function expressionInputWatch(scope) {
14345           var newInputValue = inputExpressions(scope);
14346           if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
14347             lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
14348             oldInputValueOf = newInputValue && getValueOf(newInputValue);
14349           }
14350           return lastResult;
14351         }, listener, objectEquality, prettyPrintExpression);
14352       }
14353
14354       var oldInputValueOfValues = [];
14355       var oldInputValues = [];
14356       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14357         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
14358         oldInputValues[i] = null;
14359       }
14360
14361       return scope.$watch(function expressionInputsWatch(scope) {
14362         var changed = false;
14363
14364         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14365           var newInputValue = inputExpressions[i](scope);
14366           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
14367             oldInputValues[i] = newInputValue;
14368             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
14369           }
14370         }
14371
14372         if (changed) {
14373           lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
14374         }
14375
14376         return lastResult;
14377       }, listener, objectEquality, prettyPrintExpression);
14378     }
14379
14380     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14381       var unwatch, lastValue;
14382       return unwatch = scope.$watch(function oneTimeWatch(scope) {
14383         return parsedExpression(scope);
14384       }, function oneTimeListener(value, old, scope) {
14385         lastValue = value;
14386         if (isFunction(listener)) {
14387           listener.apply(this, arguments);
14388         }
14389         if (isDefined(value)) {
14390           scope.$$postDigest(function() {
14391             if (isDefined(lastValue)) {
14392               unwatch();
14393             }
14394           });
14395         }
14396       }, objectEquality);
14397     }
14398
14399     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14400       var unwatch, lastValue;
14401       return unwatch = scope.$watch(function oneTimeWatch(scope) {
14402         return parsedExpression(scope);
14403       }, function oneTimeListener(value, old, scope) {
14404         lastValue = value;
14405         if (isFunction(listener)) {
14406           listener.call(this, value, old, scope);
14407         }
14408         if (isAllDefined(value)) {
14409           scope.$$postDigest(function() {
14410             if (isAllDefined(lastValue)) unwatch();
14411           });
14412         }
14413       }, objectEquality);
14414
14415       function isAllDefined(value) {
14416         var allDefined = true;
14417         forEach(value, function(val) {
14418           if (!isDefined(val)) allDefined = false;
14419         });
14420         return allDefined;
14421       }
14422     }
14423
14424     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14425       var unwatch;
14426       return unwatch = scope.$watch(function constantWatch(scope) {
14427         return parsedExpression(scope);
14428       }, function constantListener(value, old, scope) {
14429         if (isFunction(listener)) {
14430           listener.apply(this, arguments);
14431         }
14432         unwatch();
14433       }, objectEquality);
14434     }
14435
14436     function addInterceptor(parsedExpression, interceptorFn) {
14437       if (!interceptorFn) return parsedExpression;
14438       var watchDelegate = parsedExpression.$$watchDelegate;
14439       var useInputs = false;
14440
14441       var regularWatch =
14442           watchDelegate !== oneTimeLiteralWatchDelegate &&
14443           watchDelegate !== oneTimeWatchDelegate;
14444
14445       var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14446         var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
14447         return interceptorFn(value, scope, locals);
14448       } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14449         var value = parsedExpression(scope, locals, assign, inputs);
14450         var result = interceptorFn(value, scope, locals);
14451         // we only return the interceptor's result if the
14452         // initial value is defined (for bind-once)
14453         return isDefined(value) ? result : value;
14454       };
14455
14456       // Propagate $$watchDelegates other then inputsWatchDelegate
14457       if (parsedExpression.$$watchDelegate &&
14458           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
14459         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
14460       } else if (!interceptorFn.$stateful) {
14461         // If there is an interceptor, but no watchDelegate then treat the interceptor like
14462         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14463         fn.$$watchDelegate = inputsWatchDelegate;
14464         useInputs = !parsedExpression.inputs;
14465         fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14466       }
14467
14468       return fn;
14469     }
14470   }];
14471 }
14472
14473 /**
14474  * @ngdoc service
14475  * @name $q
14476  * @requires $rootScope
14477  *
14478  * @description
14479  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
14480  * when they are done processing.
14481  *
14482  * This is an implementation of promises/deferred objects inspired by
14483  * [Kris Kowal's Q](https://github.com/kriskowal/q).
14484  *
14485  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
14486  * implementations, and the other which resembles ES6 promises to some degree.
14487  *
14488  * # $q constructor
14489  *
14490  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
14491  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
14492  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
14493  *
14494  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
14495  * available yet.
14496  *
14497  * It can be used like so:
14498  *
14499  * ```js
14500  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14501  *   // are available in the current lexical scope (they could have been injected or passed in).
14502  *
14503  *   function asyncGreet(name) {
14504  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
14505  *     return $q(function(resolve, reject) {
14506  *       setTimeout(function() {
14507  *         if (okToGreet(name)) {
14508  *           resolve('Hello, ' + name + '!');
14509  *         } else {
14510  *           reject('Greeting ' + name + ' is not allowed.');
14511  *         }
14512  *       }, 1000);
14513  *     });
14514  *   }
14515  *
14516  *   var promise = asyncGreet('Robin Hood');
14517  *   promise.then(function(greeting) {
14518  *     alert('Success: ' + greeting);
14519  *   }, function(reason) {
14520  *     alert('Failed: ' + reason);
14521  *   });
14522  * ```
14523  *
14524  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14525  *
14526  * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
14527  *
14528  * However, the more traditional CommonJS-style usage is still available, and documented below.
14529  *
14530  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
14531  * interface for interacting with an object that represents the result of an action that is
14532  * performed asynchronously, and may or may not be finished at any given point in time.
14533  *
14534  * From the perspective of dealing with error handling, deferred and promise APIs are to
14535  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
14536  *
14537  * ```js
14538  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14539  *   // are available in the current lexical scope (they could have been injected or passed in).
14540  *
14541  *   function asyncGreet(name) {
14542  *     var deferred = $q.defer();
14543  *
14544  *     setTimeout(function() {
14545  *       deferred.notify('About to greet ' + name + '.');
14546  *
14547  *       if (okToGreet(name)) {
14548  *         deferred.resolve('Hello, ' + name + '!');
14549  *       } else {
14550  *         deferred.reject('Greeting ' + name + ' is not allowed.');
14551  *       }
14552  *     }, 1000);
14553  *
14554  *     return deferred.promise;
14555  *   }
14556  *
14557  *   var promise = asyncGreet('Robin Hood');
14558  *   promise.then(function(greeting) {
14559  *     alert('Success: ' + greeting);
14560  *   }, function(reason) {
14561  *     alert('Failed: ' + reason);
14562  *   }, function(update) {
14563  *     alert('Got notification: ' + update);
14564  *   });
14565  * ```
14566  *
14567  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
14568  * comes in the way of guarantees that promise and deferred APIs make, see
14569  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
14570  *
14571  * Additionally the promise api allows for composition that is very hard to do with the
14572  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
14573  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
14574  * section on serial or parallel joining of promises.
14575  *
14576  * # The Deferred API
14577  *
14578  * A new instance of deferred is constructed by calling `$q.defer()`.
14579  *
14580  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
14581  * that can be used for signaling the successful or unsuccessful completion, as well as the status
14582  * of the task.
14583  *
14584  * **Methods**
14585  *
14586  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
14587  *   constructed via `$q.reject`, the promise will be rejected instead.
14588  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
14589  *   resolving it with a rejection constructed via `$q.reject`.
14590  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
14591  *   multiple times before the promise is either resolved or rejected.
14592  *
14593  * **Properties**
14594  *
14595  * - promise – `{Promise}` – promise object associated with this deferred.
14596  *
14597  *
14598  * # The Promise API
14599  *
14600  * A new promise instance is created when a deferred instance is created and can be retrieved by
14601  * calling `deferred.promise`.
14602  *
14603  * The purpose of the promise object is to allow for interested parties to get access to the result
14604  * of the deferred task when it completes.
14605  *
14606  * **Methods**
14607  *
14608  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
14609  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
14610  *   as soon as the result is available. The callbacks are called with a single argument: the result
14611  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
14612  *   provide a progress indication, before the promise is resolved or rejected.
14613  *
14614  *   This method *returns a new promise* which is resolved or rejected via the return value of the
14615  *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
14616  *   with the value which is resolved in that promise using
14617  *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
14618  *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
14619  *   resolved or rejected from the notifyCallback method.
14620  *
14621  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
14622  *
14623  * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
14624  *   but to do so without modifying the final value. This is useful to release resources or do some
14625  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
14626  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
14627  *   more information.
14628  *
14629  * # Chaining promises
14630  *
14631  * Because calling the `then` method of a promise returns a new derived promise, it is easily
14632  * possible to create a chain of promises:
14633  *
14634  * ```js
14635  *   promiseB = promiseA.then(function(result) {
14636  *     return result + 1;
14637  *   });
14638  *
14639  *   // promiseB will be resolved immediately after promiseA is resolved and its value
14640  *   // will be the result of promiseA incremented by 1
14641  * ```
14642  *
14643  * It is possible to create chains of any length and since a promise can be resolved with another
14644  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
14645  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
14646  * $http's response interceptors.
14647  *
14648  *
14649  * # Differences between Kris Kowal's Q and $q
14650  *
14651  *  There are two main differences:
14652  *
14653  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
14654  *   mechanism in angular, which means faster propagation of resolution or rejection into your
14655  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
14656  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
14657  *   all the important functionality needed for common async tasks.
14658  *
14659  *  # Testing
14660  *
14661  *  ```js
14662  *    it('should simulate promise', inject(function($q, $rootScope) {
14663  *      var deferred = $q.defer();
14664  *      var promise = deferred.promise;
14665  *      var resolvedValue;
14666  *
14667  *      promise.then(function(value) { resolvedValue = value; });
14668  *      expect(resolvedValue).toBeUndefined();
14669  *
14670  *      // Simulate resolving of promise
14671  *      deferred.resolve(123);
14672  *      // Note that the 'then' function does not get called synchronously.
14673  *      // This is because we want the promise API to always be async, whether or not
14674  *      // it got called synchronously or asynchronously.
14675  *      expect(resolvedValue).toBeUndefined();
14676  *
14677  *      // Propagate promise resolution to 'then' functions using $apply().
14678  *      $rootScope.$apply();
14679  *      expect(resolvedValue).toEqual(123);
14680  *    }));
14681  *  ```
14682  *
14683  * @param {function(function, function)} resolver Function which is responsible for resolving or
14684  *   rejecting the newly created promise. The first parameter is a function which resolves the
14685  *   promise, the second parameter is a function which rejects the promise.
14686  *
14687  * @returns {Promise} The newly created promise.
14688  */
14689 function $QProvider() {
14690
14691   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
14692     return qFactory(function(callback) {
14693       $rootScope.$evalAsync(callback);
14694     }, $exceptionHandler);
14695   }];
14696 }
14697
14698 function $$QProvider() {
14699   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
14700     return qFactory(function(callback) {
14701       $browser.defer(callback);
14702     }, $exceptionHandler);
14703   }];
14704 }
14705
14706 /**
14707  * Constructs a promise manager.
14708  *
14709  * @param {function(function)} nextTick Function for executing functions in the next turn.
14710  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
14711  *     debugging purposes.
14712  * @returns {object} Promise manager.
14713  */
14714 function qFactory(nextTick, exceptionHandler) {
14715   var $qMinErr = minErr('$q', TypeError);
14716   function callOnce(self, resolveFn, rejectFn) {
14717     var called = false;
14718     function wrap(fn) {
14719       return function(value) {
14720         if (called) return;
14721         called = true;
14722         fn.call(self, value);
14723       };
14724     }
14725
14726     return [wrap(resolveFn), wrap(rejectFn)];
14727   }
14728
14729   /**
14730    * @ngdoc method
14731    * @name ng.$q#defer
14732    * @kind function
14733    *
14734    * @description
14735    * Creates a `Deferred` object which represents a task which will finish in the future.
14736    *
14737    * @returns {Deferred} Returns a new instance of deferred.
14738    */
14739   var defer = function() {
14740     return new Deferred();
14741   };
14742
14743   function Promise() {
14744     this.$$state = { status: 0 };
14745   }
14746
14747   extend(Promise.prototype, {
14748     then: function(onFulfilled, onRejected, progressBack) {
14749       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
14750         return this;
14751       }
14752       var result = new Deferred();
14753
14754       this.$$state.pending = this.$$state.pending || [];
14755       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
14756       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
14757
14758       return result.promise;
14759     },
14760
14761     "catch": function(callback) {
14762       return this.then(null, callback);
14763     },
14764
14765     "finally": function(callback, progressBack) {
14766       return this.then(function(value) {
14767         return handleCallback(value, true, callback);
14768       }, function(error) {
14769         return handleCallback(error, false, callback);
14770       }, progressBack);
14771     }
14772   });
14773
14774   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
14775   function simpleBind(context, fn) {
14776     return function(value) {
14777       fn.call(context, value);
14778     };
14779   }
14780
14781   function processQueue(state) {
14782     var fn, deferred, pending;
14783
14784     pending = state.pending;
14785     state.processScheduled = false;
14786     state.pending = undefined;
14787     for (var i = 0, ii = pending.length; i < ii; ++i) {
14788       deferred = pending[i][0];
14789       fn = pending[i][state.status];
14790       try {
14791         if (isFunction(fn)) {
14792           deferred.resolve(fn(state.value));
14793         } else if (state.status === 1) {
14794           deferred.resolve(state.value);
14795         } else {
14796           deferred.reject(state.value);
14797         }
14798       } catch (e) {
14799         deferred.reject(e);
14800         exceptionHandler(e);
14801       }
14802     }
14803   }
14804
14805   function scheduleProcessQueue(state) {
14806     if (state.processScheduled || !state.pending) return;
14807     state.processScheduled = true;
14808     nextTick(function() { processQueue(state); });
14809   }
14810
14811   function Deferred() {
14812     this.promise = new Promise();
14813     //Necessary to support unbound execution :/
14814     this.resolve = simpleBind(this, this.resolve);
14815     this.reject = simpleBind(this, this.reject);
14816     this.notify = simpleBind(this, this.notify);
14817   }
14818
14819   extend(Deferred.prototype, {
14820     resolve: function(val) {
14821       if (this.promise.$$state.status) return;
14822       if (val === this.promise) {
14823         this.$$reject($qMinErr(
14824           'qcycle',
14825           "Expected promise to be resolved with value other than itself '{0}'",
14826           val));
14827       } else {
14828         this.$$resolve(val);
14829       }
14830
14831     },
14832
14833     $$resolve: function(val) {
14834       var then, fns;
14835
14836       fns = callOnce(this, this.$$resolve, this.$$reject);
14837       try {
14838         if ((isObject(val) || isFunction(val))) then = val && val.then;
14839         if (isFunction(then)) {
14840           this.promise.$$state.status = -1;
14841           then.call(val, fns[0], fns[1], this.notify);
14842         } else {
14843           this.promise.$$state.value = val;
14844           this.promise.$$state.status = 1;
14845           scheduleProcessQueue(this.promise.$$state);
14846         }
14847       } catch (e) {
14848         fns[1](e);
14849         exceptionHandler(e);
14850       }
14851     },
14852
14853     reject: function(reason) {
14854       if (this.promise.$$state.status) return;
14855       this.$$reject(reason);
14856     },
14857
14858     $$reject: function(reason) {
14859       this.promise.$$state.value = reason;
14860       this.promise.$$state.status = 2;
14861       scheduleProcessQueue(this.promise.$$state);
14862     },
14863
14864     notify: function(progress) {
14865       var callbacks = this.promise.$$state.pending;
14866
14867       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
14868         nextTick(function() {
14869           var callback, result;
14870           for (var i = 0, ii = callbacks.length; i < ii; i++) {
14871             result = callbacks[i][0];
14872             callback = callbacks[i][3];
14873             try {
14874               result.notify(isFunction(callback) ? callback(progress) : progress);
14875             } catch (e) {
14876               exceptionHandler(e);
14877             }
14878           }
14879         });
14880       }
14881     }
14882   });
14883
14884   /**
14885    * @ngdoc method
14886    * @name $q#reject
14887    * @kind function
14888    *
14889    * @description
14890    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
14891    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
14892    * a promise chain, you don't need to worry about it.
14893    *
14894    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
14895    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
14896    * a promise error callback and you want to forward the error to the promise derived from the
14897    * current promise, you have to "rethrow" the error by returning a rejection constructed via
14898    * `reject`.
14899    *
14900    * ```js
14901    *   promiseB = promiseA.then(function(result) {
14902    *     // success: do something and resolve promiseB
14903    *     //          with the old or a new result
14904    *     return result;
14905    *   }, function(reason) {
14906    *     // error: handle the error if possible and
14907    *     //        resolve promiseB with newPromiseOrValue,
14908    *     //        otherwise forward the rejection to promiseB
14909    *     if (canHandle(reason)) {
14910    *      // handle the error and recover
14911    *      return newPromiseOrValue;
14912    *     }
14913    *     return $q.reject(reason);
14914    *   });
14915    * ```
14916    *
14917    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
14918    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
14919    */
14920   var reject = function(reason) {
14921     var result = new Deferred();
14922     result.reject(reason);
14923     return result.promise;
14924   };
14925
14926   var makePromise = function makePromise(value, resolved) {
14927     var result = new Deferred();
14928     if (resolved) {
14929       result.resolve(value);
14930     } else {
14931       result.reject(value);
14932     }
14933     return result.promise;
14934   };
14935
14936   var handleCallback = function handleCallback(value, isResolved, callback) {
14937     var callbackOutput = null;
14938     try {
14939       if (isFunction(callback)) callbackOutput = callback();
14940     } catch (e) {
14941       return makePromise(e, false);
14942     }
14943     if (isPromiseLike(callbackOutput)) {
14944       return callbackOutput.then(function() {
14945         return makePromise(value, isResolved);
14946       }, function(error) {
14947         return makePromise(error, false);
14948       });
14949     } else {
14950       return makePromise(value, isResolved);
14951     }
14952   };
14953
14954   /**
14955    * @ngdoc method
14956    * @name $q#when
14957    * @kind function
14958    *
14959    * @description
14960    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
14961    * This is useful when you are dealing with an object that might or might not be a promise, or if
14962    * the promise comes from a source that can't be trusted.
14963    *
14964    * @param {*} value Value or a promise
14965    * @param {Function=} successCallback
14966    * @param {Function=} errorCallback
14967    * @param {Function=} progressCallback
14968    * @returns {Promise} Returns a promise of the passed value or promise
14969    */
14970
14971
14972   var when = function(value, callback, errback, progressBack) {
14973     var result = new Deferred();
14974     result.resolve(value);
14975     return result.promise.then(callback, errback, progressBack);
14976   };
14977
14978   /**
14979    * @ngdoc method
14980    * @name $q#resolve
14981    * @kind function
14982    *
14983    * @description
14984    * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
14985    *
14986    * @param {*} value Value or a promise
14987    * @param {Function=} successCallback
14988    * @param {Function=} errorCallback
14989    * @param {Function=} progressCallback
14990    * @returns {Promise} Returns a promise of the passed value or promise
14991    */
14992   var resolve = when;
14993
14994   /**
14995    * @ngdoc method
14996    * @name $q#all
14997    * @kind function
14998    *
14999    * @description
15000    * Combines multiple promises into a single promise that is resolved when all of the input
15001    * promises are resolved.
15002    *
15003    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
15004    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
15005    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
15006    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
15007    *   with the same rejection value.
15008    */
15009
15010   function all(promises) {
15011     var deferred = new Deferred(),
15012         counter = 0,
15013         results = isArray(promises) ? [] : {};
15014
15015     forEach(promises, function(promise, key) {
15016       counter++;
15017       when(promise).then(function(value) {
15018         if (results.hasOwnProperty(key)) return;
15019         results[key] = value;
15020         if (!(--counter)) deferred.resolve(results);
15021       }, function(reason) {
15022         if (results.hasOwnProperty(key)) return;
15023         deferred.reject(reason);
15024       });
15025     });
15026
15027     if (counter === 0) {
15028       deferred.resolve(results);
15029     }
15030
15031     return deferred.promise;
15032   }
15033
15034   var $Q = function Q(resolver) {
15035     if (!isFunction(resolver)) {
15036       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
15037     }
15038
15039     if (!(this instanceof Q)) {
15040       // More useful when $Q is the Promise itself.
15041       return new Q(resolver);
15042     }
15043
15044     var deferred = new Deferred();
15045
15046     function resolveFn(value) {
15047       deferred.resolve(value);
15048     }
15049
15050     function rejectFn(reason) {
15051       deferred.reject(reason);
15052     }
15053
15054     resolver(resolveFn, rejectFn);
15055
15056     return deferred.promise;
15057   };
15058
15059   $Q.defer = defer;
15060   $Q.reject = reject;
15061   $Q.when = when;
15062   $Q.resolve = resolve;
15063   $Q.all = all;
15064
15065   return $Q;
15066 }
15067
15068 function $$RAFProvider() { //rAF
15069   this.$get = ['$window', '$timeout', function($window, $timeout) {
15070     var requestAnimationFrame = $window.requestAnimationFrame ||
15071                                 $window.webkitRequestAnimationFrame;
15072
15073     var cancelAnimationFrame = $window.cancelAnimationFrame ||
15074                                $window.webkitCancelAnimationFrame ||
15075                                $window.webkitCancelRequestAnimationFrame;
15076
15077     var rafSupported = !!requestAnimationFrame;
15078     var raf = rafSupported
15079       ? function(fn) {
15080           var id = requestAnimationFrame(fn);
15081           return function() {
15082             cancelAnimationFrame(id);
15083           };
15084         }
15085       : function(fn) {
15086           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
15087           return function() {
15088             $timeout.cancel(timer);
15089           };
15090         };
15091
15092     raf.supported = rafSupported;
15093
15094     return raf;
15095   }];
15096 }
15097
15098 /**
15099  * DESIGN NOTES
15100  *
15101  * The design decisions behind the scope are heavily favored for speed and memory consumption.
15102  *
15103  * The typical use of scope is to watch the expressions, which most of the time return the same
15104  * value as last time so we optimize the operation.
15105  *
15106  * Closures construction is expensive in terms of speed as well as memory:
15107  *   - No closures, instead use prototypical inheritance for API
15108  *   - Internal state needs to be stored on scope directly, which means that private state is
15109  *     exposed as $$____ properties
15110  *
15111  * Loop operations are optimized by using while(count--) { ... }
15112  *   - This means that in order to keep the same order of execution as addition we have to add
15113  *     items to the array at the beginning (unshift) instead of at the end (push)
15114  *
15115  * Child scopes are created and removed often
15116  *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
15117  *
15118  * There are fewer watches than observers. This is why you don't want the observer to be implemented
15119  * in the same way as watch. Watch requires return of the initialization function which is expensive
15120  * to construct.
15121  */
15122
15123
15124 /**
15125  * @ngdoc provider
15126  * @name $rootScopeProvider
15127  * @description
15128  *
15129  * Provider for the $rootScope service.
15130  */
15131
15132 /**
15133  * @ngdoc method
15134  * @name $rootScopeProvider#digestTtl
15135  * @description
15136  *
15137  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
15138  * assuming that the model is unstable.
15139  *
15140  * The current default is 10 iterations.
15141  *
15142  * In complex applications it's possible that the dependencies between `$watch`s will result in
15143  * several digest iterations. However if an application needs more than the default 10 digest
15144  * iterations for its model to stabilize then you should investigate what is causing the model to
15145  * continuously change during the digest.
15146  *
15147  * Increasing the TTL could have performance implications, so you should not change it without
15148  * proper justification.
15149  *
15150  * @param {number} limit The number of digest iterations.
15151  */
15152
15153
15154 /**
15155  * @ngdoc service
15156  * @name $rootScope
15157  * @description
15158  *
15159  * Every application has a single root {@link ng.$rootScope.Scope scope}.
15160  * All other scopes are descendant scopes of the root scope. Scopes provide separation
15161  * between the model and the view, via a mechanism for watching the model for changes.
15162  * They also provide event emission/broadcast and subscription facility. See the
15163  * {@link guide/scope developer guide on scopes}.
15164  */
15165 function $RootScopeProvider() {
15166   var TTL = 10;
15167   var $rootScopeMinErr = minErr('$rootScope');
15168   var lastDirtyWatch = null;
15169   var applyAsyncId = null;
15170
15171   this.digestTtl = function(value) {
15172     if (arguments.length) {
15173       TTL = value;
15174     }
15175     return TTL;
15176   };
15177
15178   function createChildScopeClass(parent) {
15179     function ChildScope() {
15180       this.$$watchers = this.$$nextSibling =
15181           this.$$childHead = this.$$childTail = null;
15182       this.$$listeners = {};
15183       this.$$listenerCount = {};
15184       this.$$watchersCount = 0;
15185       this.$id = nextUid();
15186       this.$$ChildScope = null;
15187     }
15188     ChildScope.prototype = parent;
15189     return ChildScope;
15190   }
15191
15192   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
15193       function($injector, $exceptionHandler, $parse, $browser) {
15194
15195     function destroyChildScope($event) {
15196         $event.currentScope.$$destroyed = true;
15197     }
15198
15199     function cleanUpScope($scope) {
15200
15201       if (msie === 9) {
15202         // There is a memory leak in IE9 if all child scopes are not disconnected
15203         // completely when a scope is destroyed. So this code will recurse up through
15204         // all this scopes children
15205         //
15206         // See issue https://github.com/angular/angular.js/issues/10706
15207         $scope.$$childHead && cleanUpScope($scope.$$childHead);
15208         $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
15209       }
15210
15211       // The code below works around IE9 and V8's memory leaks
15212       //
15213       // See:
15214       // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15215       // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15216       // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15217
15218       $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
15219           $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
15220     }
15221
15222     /**
15223      * @ngdoc type
15224      * @name $rootScope.Scope
15225      *
15226      * @description
15227      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
15228      * {@link auto.$injector $injector}. Child scopes are created using the
15229      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
15230      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
15231      * an in-depth introduction and usage examples.
15232      *
15233      *
15234      * # Inheritance
15235      * A scope can inherit from a parent scope, as in this example:
15236      * ```js
15237          var parent = $rootScope;
15238          var child = parent.$new();
15239
15240          parent.salutation = "Hello";
15241          expect(child.salutation).toEqual('Hello');
15242
15243          child.salutation = "Welcome";
15244          expect(child.salutation).toEqual('Welcome');
15245          expect(parent.salutation).toEqual('Hello');
15246      * ```
15247      *
15248      * When interacting with `Scope` in tests, additional helper methods are available on the
15249      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
15250      * details.
15251      *
15252      *
15253      * @param {Object.<string, function()>=} providers Map of service factory which need to be
15254      *                                       provided for the current scope. Defaults to {@link ng}.
15255      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
15256      *                              append/override services provided by `providers`. This is handy
15257      *                              when unit-testing and having the need to override a default
15258      *                              service.
15259      * @returns {Object} Newly created scope.
15260      *
15261      */
15262     function Scope() {
15263       this.$id = nextUid();
15264       this.$$phase = this.$parent = this.$$watchers =
15265                      this.$$nextSibling = this.$$prevSibling =
15266                      this.$$childHead = this.$$childTail = null;
15267       this.$root = this;
15268       this.$$destroyed = false;
15269       this.$$listeners = {};
15270       this.$$listenerCount = {};
15271       this.$$watchersCount = 0;
15272       this.$$isolateBindings = null;
15273     }
15274
15275     /**
15276      * @ngdoc property
15277      * @name $rootScope.Scope#$id
15278      *
15279      * @description
15280      * Unique scope ID (monotonically increasing) useful for debugging.
15281      */
15282
15283      /**
15284       * @ngdoc property
15285       * @name $rootScope.Scope#$parent
15286       *
15287       * @description
15288       * Reference to the parent scope.
15289       */
15290
15291       /**
15292        * @ngdoc property
15293        * @name $rootScope.Scope#$root
15294        *
15295        * @description
15296        * Reference to the root scope.
15297        */
15298
15299     Scope.prototype = {
15300       constructor: Scope,
15301       /**
15302        * @ngdoc method
15303        * @name $rootScope.Scope#$new
15304        * @kind function
15305        *
15306        * @description
15307        * Creates a new child {@link ng.$rootScope.Scope scope}.
15308        *
15309        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
15310        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
15311        *
15312        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
15313        * desired for the scope and its child scopes to be permanently detached from the parent and
15314        * thus stop participating in model change detection and listener notification by invoking.
15315        *
15316        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
15317        *         parent scope. The scope is isolated, as it can not see parent scope properties.
15318        *         When creating widgets, it is useful for the widget to not accidentally read parent
15319        *         state.
15320        *
15321        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
15322        *                              of the newly created scope. Defaults to `this` scope if not provided.
15323        *                              This is used when creating a transclude scope to correctly place it
15324        *                              in the scope hierarchy while maintaining the correct prototypical
15325        *                              inheritance.
15326        *
15327        * @returns {Object} The newly created child scope.
15328        *
15329        */
15330       $new: function(isolate, parent) {
15331         var child;
15332
15333         parent = parent || this;
15334
15335         if (isolate) {
15336           child = new Scope();
15337           child.$root = this.$root;
15338         } else {
15339           // Only create a child scope class if somebody asks for one,
15340           // but cache it to allow the VM to optimize lookups.
15341           if (!this.$$ChildScope) {
15342             this.$$ChildScope = createChildScopeClass(this);
15343           }
15344           child = new this.$$ChildScope();
15345         }
15346         child.$parent = parent;
15347         child.$$prevSibling = parent.$$childTail;
15348         if (parent.$$childHead) {
15349           parent.$$childTail.$$nextSibling = child;
15350           parent.$$childTail = child;
15351         } else {
15352           parent.$$childHead = parent.$$childTail = child;
15353         }
15354
15355         // When the new scope is not isolated or we inherit from `this`, and
15356         // the parent scope is destroyed, the property `$$destroyed` is inherited
15357         // prototypically. In all other cases, this property needs to be set
15358         // when the parent scope is destroyed.
15359         // The listener needs to be added after the parent is set
15360         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
15361
15362         return child;
15363       },
15364
15365       /**
15366        * @ngdoc method
15367        * @name $rootScope.Scope#$watch
15368        * @kind function
15369        *
15370        * @description
15371        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
15372        *
15373        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
15374        *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
15375        *   its value when executed multiple times with the same input because it may be executed multiple
15376        *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
15377        *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
15378        * - The `listener` is called only when the value from the current `watchExpression` and the
15379        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
15380        *   see below). Inequality is determined according to reference inequality,
15381        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
15382        *    via the `!==` Javascript operator, unless `objectEquality == true`
15383        *   (see next point)
15384        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
15385        *   according to the {@link angular.equals} function. To save the value of the object for
15386        *   later comparison, the {@link angular.copy} function is used. This therefore means that
15387        *   watching complex objects will have adverse memory and performance implications.
15388        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
15389        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
15390        *   iteration limit is 10 to prevent an infinite loop deadlock.
15391        *
15392        *
15393        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
15394        * you can register a `watchExpression` function with no `listener`. (Be prepared for
15395        * multiple calls to your `watchExpression` because it will execute multiple times in a
15396        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
15397        *
15398        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
15399        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
15400        * watcher. In rare cases, this is undesirable because the listener is called when the result
15401        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
15402        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
15403        * listener was called due to initialization.
15404        *
15405        *
15406        *
15407        * # Example
15408        * ```js
15409            // let's assume that scope was dependency injected as the $rootScope
15410            var scope = $rootScope;
15411            scope.name = 'misko';
15412            scope.counter = 0;
15413
15414            expect(scope.counter).toEqual(0);
15415            scope.$watch('name', function(newValue, oldValue) {
15416              scope.counter = scope.counter + 1;
15417            });
15418            expect(scope.counter).toEqual(0);
15419
15420            scope.$digest();
15421            // the listener is always called during the first $digest loop after it was registered
15422            expect(scope.counter).toEqual(1);
15423
15424            scope.$digest();
15425            // but now it will not be called unless the value changes
15426            expect(scope.counter).toEqual(1);
15427
15428            scope.name = 'adam';
15429            scope.$digest();
15430            expect(scope.counter).toEqual(2);
15431
15432
15433
15434            // Using a function as a watchExpression
15435            var food;
15436            scope.foodCounter = 0;
15437            expect(scope.foodCounter).toEqual(0);
15438            scope.$watch(
15439              // This function returns the value being watched. It is called for each turn of the $digest loop
15440              function() { return food; },
15441              // This is the change listener, called when the value returned from the above function changes
15442              function(newValue, oldValue) {
15443                if ( newValue !== oldValue ) {
15444                  // Only increment the counter if the value changed
15445                  scope.foodCounter = scope.foodCounter + 1;
15446                }
15447              }
15448            );
15449            // No digest has been run so the counter will be zero
15450            expect(scope.foodCounter).toEqual(0);
15451
15452            // Run the digest but since food has not changed count will still be zero
15453            scope.$digest();
15454            expect(scope.foodCounter).toEqual(0);
15455
15456            // Update food and run digest.  Now the counter will increment
15457            food = 'cheeseburger';
15458            scope.$digest();
15459            expect(scope.foodCounter).toEqual(1);
15460
15461        * ```
15462        *
15463        *
15464        *
15465        * @param {(function()|string)} watchExpression Expression that is evaluated on each
15466        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
15467        *    a call to the `listener`.
15468        *
15469        *    - `string`: Evaluated as {@link guide/expression expression}
15470        *    - `function(scope)`: called with current `scope` as a parameter.
15471        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
15472        *    of `watchExpression` changes.
15473        *
15474        *    - `newVal` contains the current value of the `watchExpression`
15475        *    - `oldVal` contains the previous value of the `watchExpression`
15476        *    - `scope` refers to the current scope
15477        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
15478        *     comparing for reference equality.
15479        * @returns {function()} Returns a deregistration function for this listener.
15480        */
15481       $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
15482         var get = $parse(watchExp);
15483
15484         if (get.$$watchDelegate) {
15485           return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
15486         }
15487         var scope = this,
15488             array = scope.$$watchers,
15489             watcher = {
15490               fn: listener,
15491               last: initWatchVal,
15492               get: get,
15493               exp: prettyPrintExpression || watchExp,
15494               eq: !!objectEquality
15495             };
15496
15497         lastDirtyWatch = null;
15498
15499         if (!isFunction(listener)) {
15500           watcher.fn = noop;
15501         }
15502
15503         if (!array) {
15504           array = scope.$$watchers = [];
15505         }
15506         // we use unshift since we use a while loop in $digest for speed.
15507         // the while loop reads in reverse order.
15508         array.unshift(watcher);
15509         incrementWatchersCount(this, 1);
15510
15511         return function deregisterWatch() {
15512           if (arrayRemove(array, watcher) >= 0) {
15513             incrementWatchersCount(scope, -1);
15514           }
15515           lastDirtyWatch = null;
15516         };
15517       },
15518
15519       /**
15520        * @ngdoc method
15521        * @name $rootScope.Scope#$watchGroup
15522        * @kind function
15523        *
15524        * @description
15525        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
15526        * If any one expression in the collection changes the `listener` is executed.
15527        *
15528        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
15529        *   call to $digest() to see if any items changes.
15530        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
15531        *
15532        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
15533        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
15534        *
15535        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
15536        *    expression in `watchExpressions` changes
15537        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
15538        *    those of `watchExpression`
15539        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
15540        *    those of `watchExpression`
15541        *    The `scope` refers to the current scope.
15542        * @returns {function()} Returns a de-registration function for all listeners.
15543        */
15544       $watchGroup: function(watchExpressions, listener) {
15545         var oldValues = new Array(watchExpressions.length);
15546         var newValues = new Array(watchExpressions.length);
15547         var deregisterFns = [];
15548         var self = this;
15549         var changeReactionScheduled = false;
15550         var firstRun = true;
15551
15552         if (!watchExpressions.length) {
15553           // No expressions means we call the listener ASAP
15554           var shouldCall = true;
15555           self.$evalAsync(function() {
15556             if (shouldCall) listener(newValues, newValues, self);
15557           });
15558           return function deregisterWatchGroup() {
15559             shouldCall = false;
15560           };
15561         }
15562
15563         if (watchExpressions.length === 1) {
15564           // Special case size of one
15565           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
15566             newValues[0] = value;
15567             oldValues[0] = oldValue;
15568             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
15569           });
15570         }
15571
15572         forEach(watchExpressions, function(expr, i) {
15573           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
15574             newValues[i] = value;
15575             oldValues[i] = oldValue;
15576             if (!changeReactionScheduled) {
15577               changeReactionScheduled = true;
15578               self.$evalAsync(watchGroupAction);
15579             }
15580           });
15581           deregisterFns.push(unwatchFn);
15582         });
15583
15584         function watchGroupAction() {
15585           changeReactionScheduled = false;
15586
15587           if (firstRun) {
15588             firstRun = false;
15589             listener(newValues, newValues, self);
15590           } else {
15591             listener(newValues, oldValues, self);
15592           }
15593         }
15594
15595         return function deregisterWatchGroup() {
15596           while (deregisterFns.length) {
15597             deregisterFns.shift()();
15598           }
15599         };
15600       },
15601
15602
15603       /**
15604        * @ngdoc method
15605        * @name $rootScope.Scope#$watchCollection
15606        * @kind function
15607        *
15608        * @description
15609        * Shallow watches the properties of an object and fires whenever any of the properties change
15610        * (for arrays, this implies watching the array items; for object maps, this implies watching
15611        * the properties). If a change is detected, the `listener` callback is fired.
15612        *
15613        * - The `obj` collection is observed via standard $watch operation and is examined on every
15614        *   call to $digest() to see if any items have been added, removed, or moved.
15615        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
15616        *   adding, removing, and moving items belonging to an object or array.
15617        *
15618        *
15619        * # Example
15620        * ```js
15621           $scope.names = ['igor', 'matias', 'misko', 'james'];
15622           $scope.dataCount = 4;
15623
15624           $scope.$watchCollection('names', function(newNames, oldNames) {
15625             $scope.dataCount = newNames.length;
15626           });
15627
15628           expect($scope.dataCount).toEqual(4);
15629           $scope.$digest();
15630
15631           //still at 4 ... no changes
15632           expect($scope.dataCount).toEqual(4);
15633
15634           $scope.names.pop();
15635           $scope.$digest();
15636
15637           //now there's been a change
15638           expect($scope.dataCount).toEqual(3);
15639        * ```
15640        *
15641        *
15642        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
15643        *    expression value should evaluate to an object or an array which is observed on each
15644        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
15645        *    collection will trigger a call to the `listener`.
15646        *
15647        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
15648        *    when a change is detected.
15649        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
15650        *    - The `oldCollection` object is a copy of the former collection data.
15651        *      Due to performance considerations, the`oldCollection` value is computed only if the
15652        *      `listener` function declares two or more arguments.
15653        *    - The `scope` argument refers to the current scope.
15654        *
15655        * @returns {function()} Returns a de-registration function for this listener. When the
15656        *    de-registration function is executed, the internal watch operation is terminated.
15657        */
15658       $watchCollection: function(obj, listener) {
15659         $watchCollectionInterceptor.$stateful = true;
15660
15661         var self = this;
15662         // the current value, updated on each dirty-check run
15663         var newValue;
15664         // a shallow copy of the newValue from the last dirty-check run,
15665         // updated to match newValue during dirty-check run
15666         var oldValue;
15667         // a shallow copy of the newValue from when the last change happened
15668         var veryOldValue;
15669         // only track veryOldValue if the listener is asking for it
15670         var trackVeryOldValue = (listener.length > 1);
15671         var changeDetected = 0;
15672         var changeDetector = $parse(obj, $watchCollectionInterceptor);
15673         var internalArray = [];
15674         var internalObject = {};
15675         var initRun = true;
15676         var oldLength = 0;
15677
15678         function $watchCollectionInterceptor(_value) {
15679           newValue = _value;
15680           var newLength, key, bothNaN, newItem, oldItem;
15681
15682           // If the new value is undefined, then return undefined as the watch may be a one-time watch
15683           if (isUndefined(newValue)) return;
15684
15685           if (!isObject(newValue)) { // if primitive
15686             if (oldValue !== newValue) {
15687               oldValue = newValue;
15688               changeDetected++;
15689             }
15690           } else if (isArrayLike(newValue)) {
15691             if (oldValue !== internalArray) {
15692               // we are transitioning from something which was not an array into array.
15693               oldValue = internalArray;
15694               oldLength = oldValue.length = 0;
15695               changeDetected++;
15696             }
15697
15698             newLength = newValue.length;
15699
15700             if (oldLength !== newLength) {
15701               // if lengths do not match we need to trigger change notification
15702               changeDetected++;
15703               oldValue.length = oldLength = newLength;
15704             }
15705             // copy the items to oldValue and look for changes.
15706             for (var i = 0; i < newLength; i++) {
15707               oldItem = oldValue[i];
15708               newItem = newValue[i];
15709
15710               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15711               if (!bothNaN && (oldItem !== newItem)) {
15712                 changeDetected++;
15713                 oldValue[i] = newItem;
15714               }
15715             }
15716           } else {
15717             if (oldValue !== internalObject) {
15718               // we are transitioning from something which was not an object into object.
15719               oldValue = internalObject = {};
15720               oldLength = 0;
15721               changeDetected++;
15722             }
15723             // copy the items to oldValue and look for changes.
15724             newLength = 0;
15725             for (key in newValue) {
15726               if (hasOwnProperty.call(newValue, key)) {
15727                 newLength++;
15728                 newItem = newValue[key];
15729                 oldItem = oldValue[key];
15730
15731                 if (key in oldValue) {
15732                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15733                   if (!bothNaN && (oldItem !== newItem)) {
15734                     changeDetected++;
15735                     oldValue[key] = newItem;
15736                   }
15737                 } else {
15738                   oldLength++;
15739                   oldValue[key] = newItem;
15740                   changeDetected++;
15741                 }
15742               }
15743             }
15744             if (oldLength > newLength) {
15745               // we used to have more keys, need to find them and destroy them.
15746               changeDetected++;
15747               for (key in oldValue) {
15748                 if (!hasOwnProperty.call(newValue, key)) {
15749                   oldLength--;
15750                   delete oldValue[key];
15751                 }
15752               }
15753             }
15754           }
15755           return changeDetected;
15756         }
15757
15758         function $watchCollectionAction() {
15759           if (initRun) {
15760             initRun = false;
15761             listener(newValue, newValue, self);
15762           } else {
15763             listener(newValue, veryOldValue, self);
15764           }
15765
15766           // make a copy for the next time a collection is changed
15767           if (trackVeryOldValue) {
15768             if (!isObject(newValue)) {
15769               //primitive
15770               veryOldValue = newValue;
15771             } else if (isArrayLike(newValue)) {
15772               veryOldValue = new Array(newValue.length);
15773               for (var i = 0; i < newValue.length; i++) {
15774                 veryOldValue[i] = newValue[i];
15775               }
15776             } else { // if object
15777               veryOldValue = {};
15778               for (var key in newValue) {
15779                 if (hasOwnProperty.call(newValue, key)) {
15780                   veryOldValue[key] = newValue[key];
15781                 }
15782               }
15783             }
15784           }
15785         }
15786
15787         return this.$watch(changeDetector, $watchCollectionAction);
15788       },
15789
15790       /**
15791        * @ngdoc method
15792        * @name $rootScope.Scope#$digest
15793        * @kind function
15794        *
15795        * @description
15796        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
15797        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
15798        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
15799        * until no more listeners are firing. This means that it is possible to get into an infinite
15800        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
15801        * iterations exceeds 10.
15802        *
15803        * Usually, you don't call `$digest()` directly in
15804        * {@link ng.directive:ngController controllers} or in
15805        * {@link ng.$compileProvider#directive directives}.
15806        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
15807        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
15808        *
15809        * If you want to be notified whenever `$digest()` is called,
15810        * you can register a `watchExpression` function with
15811        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
15812        *
15813        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
15814        *
15815        * # Example
15816        * ```js
15817            var scope = ...;
15818            scope.name = 'misko';
15819            scope.counter = 0;
15820
15821            expect(scope.counter).toEqual(0);
15822            scope.$watch('name', function(newValue, oldValue) {
15823              scope.counter = scope.counter + 1;
15824            });
15825            expect(scope.counter).toEqual(0);
15826
15827            scope.$digest();
15828            // the listener is always called during the first $digest loop after it was registered
15829            expect(scope.counter).toEqual(1);
15830
15831            scope.$digest();
15832            // but now it will not be called unless the value changes
15833            expect(scope.counter).toEqual(1);
15834
15835            scope.name = 'adam';
15836            scope.$digest();
15837            expect(scope.counter).toEqual(2);
15838        * ```
15839        *
15840        */
15841       $digest: function() {
15842         var watch, value, last,
15843             watchers,
15844             length,
15845             dirty, ttl = TTL,
15846             next, current, target = this,
15847             watchLog = [],
15848             logIdx, logMsg, asyncTask;
15849
15850         beginPhase('$digest');
15851         // Check for changes to browser url that happened in sync before the call to $digest
15852         $browser.$$checkUrlChange();
15853
15854         if (this === $rootScope && applyAsyncId !== null) {
15855           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
15856           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
15857           $browser.defer.cancel(applyAsyncId);
15858           flushApplyAsync();
15859         }
15860
15861         lastDirtyWatch = null;
15862
15863         do { // "while dirty" loop
15864           dirty = false;
15865           current = target;
15866
15867           while (asyncQueue.length) {
15868             try {
15869               asyncTask = asyncQueue.shift();
15870               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
15871             } catch (e) {
15872               $exceptionHandler(e);
15873             }
15874             lastDirtyWatch = null;
15875           }
15876
15877           traverseScopesLoop:
15878           do { // "traverse the scopes" loop
15879             if ((watchers = current.$$watchers)) {
15880               // process our watches
15881               length = watchers.length;
15882               while (length--) {
15883                 try {
15884                   watch = watchers[length];
15885                   // Most common watches are on primitives, in which case we can short
15886                   // circuit it with === operator, only when === fails do we use .equals
15887                   if (watch) {
15888                     if ((value = watch.get(current)) !== (last = watch.last) &&
15889                         !(watch.eq
15890                             ? equals(value, last)
15891                             : (typeof value === 'number' && typeof last === 'number'
15892                                && isNaN(value) && isNaN(last)))) {
15893                       dirty = true;
15894                       lastDirtyWatch = watch;
15895                       watch.last = watch.eq ? copy(value, null) : value;
15896                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
15897                       if (ttl < 5) {
15898                         logIdx = 4 - ttl;
15899                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
15900                         watchLog[logIdx].push({
15901                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
15902                           newVal: value,
15903                           oldVal: last
15904                         });
15905                       }
15906                     } else if (watch === lastDirtyWatch) {
15907                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
15908                       // have already been tested.
15909                       dirty = false;
15910                       break traverseScopesLoop;
15911                     }
15912                   }
15913                 } catch (e) {
15914                   $exceptionHandler(e);
15915                 }
15916               }
15917             }
15918
15919             // Insanity Warning: scope depth-first traversal
15920             // yes, this code is a bit crazy, but it works and we have tests to prove it!
15921             // this piece should be kept in sync with the traversal in $broadcast
15922             if (!(next = ((current.$$watchersCount && current.$$childHead) ||
15923                 (current !== target && current.$$nextSibling)))) {
15924               while (current !== target && !(next = current.$$nextSibling)) {
15925                 current = current.$parent;
15926               }
15927             }
15928           } while ((current = next));
15929
15930           // `break traverseScopesLoop;` takes us to here
15931
15932           if ((dirty || asyncQueue.length) && !(ttl--)) {
15933             clearPhase();
15934             throw $rootScopeMinErr('infdig',
15935                 '{0} $digest() iterations reached. Aborting!\n' +
15936                 'Watchers fired in the last 5 iterations: {1}',
15937                 TTL, watchLog);
15938           }
15939
15940         } while (dirty || asyncQueue.length);
15941
15942         clearPhase();
15943
15944         while (postDigestQueue.length) {
15945           try {
15946             postDigestQueue.shift()();
15947           } catch (e) {
15948             $exceptionHandler(e);
15949           }
15950         }
15951       },
15952
15953
15954       /**
15955        * @ngdoc event
15956        * @name $rootScope.Scope#$destroy
15957        * @eventType broadcast on scope being destroyed
15958        *
15959        * @description
15960        * Broadcasted when a scope and its children are being destroyed.
15961        *
15962        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
15963        * clean up DOM bindings before an element is removed from the DOM.
15964        */
15965
15966       /**
15967        * @ngdoc method
15968        * @name $rootScope.Scope#$destroy
15969        * @kind function
15970        *
15971        * @description
15972        * Removes the current scope (and all of its children) from the parent scope. Removal implies
15973        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
15974        * propagate to the current scope and its children. Removal also implies that the current
15975        * scope is eligible for garbage collection.
15976        *
15977        * The `$destroy()` is usually used by directives such as
15978        * {@link ng.directive:ngRepeat ngRepeat} for managing the
15979        * unrolling of the loop.
15980        *
15981        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
15982        * Application code can register a `$destroy` event handler that will give it a chance to
15983        * perform any necessary cleanup.
15984        *
15985        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
15986        * clean up DOM bindings before an element is removed from the DOM.
15987        */
15988       $destroy: function() {
15989         // We can't destroy a scope that has been already destroyed.
15990         if (this.$$destroyed) return;
15991         var parent = this.$parent;
15992
15993         this.$broadcast('$destroy');
15994         this.$$destroyed = true;
15995
15996         if (this === $rootScope) {
15997           //Remove handlers attached to window when $rootScope is removed
15998           $browser.$$applicationDestroyed();
15999         }
16000
16001         incrementWatchersCount(this, -this.$$watchersCount);
16002         for (var eventName in this.$$listenerCount) {
16003           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
16004         }
16005
16006         // sever all the references to parent scopes (after this cleanup, the current scope should
16007         // not be retained by any of our references and should be eligible for garbage collection)
16008         if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
16009         if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
16010         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
16011         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
16012
16013         // Disable listeners, watchers and apply/digest methods
16014         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
16015         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
16016         this.$$listeners = {};
16017
16018         // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
16019         this.$$nextSibling = null;
16020         cleanUpScope(this);
16021       },
16022
16023       /**
16024        * @ngdoc method
16025        * @name $rootScope.Scope#$eval
16026        * @kind function
16027        *
16028        * @description
16029        * Executes the `expression` on the current scope and returns the result. Any exceptions in
16030        * the expression are propagated (uncaught). This is useful when evaluating Angular
16031        * expressions.
16032        *
16033        * # Example
16034        * ```js
16035            var scope = ng.$rootScope.Scope();
16036            scope.a = 1;
16037            scope.b = 2;
16038
16039            expect(scope.$eval('a+b')).toEqual(3);
16040            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
16041        * ```
16042        *
16043        * @param {(string|function())=} expression An angular expression to be executed.
16044        *
16045        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
16046        *    - `function(scope)`: execute the function with the current `scope` parameter.
16047        *
16048        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16049        * @returns {*} The result of evaluating the expression.
16050        */
16051       $eval: function(expr, locals) {
16052         return $parse(expr)(this, locals);
16053       },
16054
16055       /**
16056        * @ngdoc method
16057        * @name $rootScope.Scope#$evalAsync
16058        * @kind function
16059        *
16060        * @description
16061        * Executes the expression on the current scope at a later point in time.
16062        *
16063        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
16064        * that:
16065        *
16066        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
16067        *     rendering).
16068        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
16069        *     `expression` execution.
16070        *
16071        * Any exceptions from the execution of the expression are forwarded to the
16072        * {@link ng.$exceptionHandler $exceptionHandler} service.
16073        *
16074        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
16075        * will be scheduled. However, it is encouraged to always call code that changes the model
16076        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
16077        *
16078        * @param {(string|function())=} expression An angular expression to be executed.
16079        *
16080        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16081        *    - `function(scope)`: execute the function with the current `scope` parameter.
16082        *
16083        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16084        */
16085       $evalAsync: function(expr, locals) {
16086         // if we are outside of an $digest loop and this is the first time we are scheduling async
16087         // task also schedule async auto-flush
16088         if (!$rootScope.$$phase && !asyncQueue.length) {
16089           $browser.defer(function() {
16090             if (asyncQueue.length) {
16091               $rootScope.$digest();
16092             }
16093           });
16094         }
16095
16096         asyncQueue.push({scope: this, expression: expr, locals: locals});
16097       },
16098
16099       $$postDigest: function(fn) {
16100         postDigestQueue.push(fn);
16101       },
16102
16103       /**
16104        * @ngdoc method
16105        * @name $rootScope.Scope#$apply
16106        * @kind function
16107        *
16108        * @description
16109        * `$apply()` is used to execute an expression in angular from outside of the angular
16110        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
16111        * Because we are calling into the angular framework we need to perform proper scope life
16112        * cycle of {@link ng.$exceptionHandler exception handling},
16113        * {@link ng.$rootScope.Scope#$digest executing watches}.
16114        *
16115        * ## Life cycle
16116        *
16117        * # Pseudo-Code of `$apply()`
16118        * ```js
16119            function $apply(expr) {
16120              try {
16121                return $eval(expr);
16122              } catch (e) {
16123                $exceptionHandler(e);
16124              } finally {
16125                $root.$digest();
16126              }
16127            }
16128        * ```
16129        *
16130        *
16131        * Scope's `$apply()` method transitions through the following stages:
16132        *
16133        * 1. The {@link guide/expression expression} is executed using the
16134        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
16135        * 2. Any exceptions from the execution of the expression are forwarded to the
16136        *    {@link ng.$exceptionHandler $exceptionHandler} service.
16137        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
16138        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
16139        *
16140        *
16141        * @param {(string|function())=} exp An angular expression to be executed.
16142        *
16143        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16144        *    - `function(scope)`: execute the function with current `scope` parameter.
16145        *
16146        * @returns {*} The result of evaluating the expression.
16147        */
16148       $apply: function(expr) {
16149         try {
16150           beginPhase('$apply');
16151           try {
16152             return this.$eval(expr);
16153           } finally {
16154             clearPhase();
16155           }
16156         } catch (e) {
16157           $exceptionHandler(e);
16158         } finally {
16159           try {
16160             $rootScope.$digest();
16161           } catch (e) {
16162             $exceptionHandler(e);
16163             throw e;
16164           }
16165         }
16166       },
16167
16168       /**
16169        * @ngdoc method
16170        * @name $rootScope.Scope#$applyAsync
16171        * @kind function
16172        *
16173        * @description
16174        * Schedule the invocation of $apply to occur at a later time. The actual time difference
16175        * varies across browsers, but is typically around ~10 milliseconds.
16176        *
16177        * This can be used to queue up multiple expressions which need to be evaluated in the same
16178        * digest.
16179        *
16180        * @param {(string|function())=} exp An angular expression to be executed.
16181        *
16182        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16183        *    - `function(scope)`: execute the function with current `scope` parameter.
16184        */
16185       $applyAsync: function(expr) {
16186         var scope = this;
16187         expr && applyAsyncQueue.push($applyAsyncExpression);
16188         scheduleApplyAsync();
16189
16190         function $applyAsyncExpression() {
16191           scope.$eval(expr);
16192         }
16193       },
16194
16195       /**
16196        * @ngdoc method
16197        * @name $rootScope.Scope#$on
16198        * @kind function
16199        *
16200        * @description
16201        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
16202        * discussion of event life cycle.
16203        *
16204        * The event listener function format is: `function(event, args...)`. The `event` object
16205        * passed into the listener has the following attributes:
16206        *
16207        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
16208        *     `$broadcast`-ed.
16209        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
16210        *     event propagates through the scope hierarchy, this property is set to null.
16211        *   - `name` - `{string}`: name of the event.
16212        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
16213        *     further event propagation (available only for events that were `$emit`-ed).
16214        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
16215        *     to true.
16216        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
16217        *
16218        * @param {string} name Event name to listen on.
16219        * @param {function(event, ...args)} listener Function to call when the event is emitted.
16220        * @returns {function()} Returns a deregistration function for this listener.
16221        */
16222       $on: function(name, listener) {
16223         var namedListeners = this.$$listeners[name];
16224         if (!namedListeners) {
16225           this.$$listeners[name] = namedListeners = [];
16226         }
16227         namedListeners.push(listener);
16228
16229         var current = this;
16230         do {
16231           if (!current.$$listenerCount[name]) {
16232             current.$$listenerCount[name] = 0;
16233           }
16234           current.$$listenerCount[name]++;
16235         } while ((current = current.$parent));
16236
16237         var self = this;
16238         return function() {
16239           var indexOfListener = namedListeners.indexOf(listener);
16240           if (indexOfListener !== -1) {
16241             namedListeners[indexOfListener] = null;
16242             decrementListenerCount(self, 1, name);
16243           }
16244         };
16245       },
16246
16247
16248       /**
16249        * @ngdoc method
16250        * @name $rootScope.Scope#$emit
16251        * @kind function
16252        *
16253        * @description
16254        * Dispatches an event `name` upwards through the scope hierarchy notifying the
16255        * registered {@link ng.$rootScope.Scope#$on} listeners.
16256        *
16257        * The event life cycle starts at the scope on which `$emit` was called. All
16258        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16259        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
16260        * registered listeners along the way. The event will stop propagating if one of the listeners
16261        * cancels it.
16262        *
16263        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16264        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16265        *
16266        * @param {string} name Event name to emit.
16267        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16268        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
16269        */
16270       $emit: function(name, args) {
16271         var empty = [],
16272             namedListeners,
16273             scope = this,
16274             stopPropagation = false,
16275             event = {
16276               name: name,
16277               targetScope: scope,
16278               stopPropagation: function() {stopPropagation = true;},
16279               preventDefault: function() {
16280                 event.defaultPrevented = true;
16281               },
16282               defaultPrevented: false
16283             },
16284             listenerArgs = concat([event], arguments, 1),
16285             i, length;
16286
16287         do {
16288           namedListeners = scope.$$listeners[name] || empty;
16289           event.currentScope = scope;
16290           for (i = 0, length = namedListeners.length; i < length; i++) {
16291
16292             // if listeners were deregistered, defragment the array
16293             if (!namedListeners[i]) {
16294               namedListeners.splice(i, 1);
16295               i--;
16296               length--;
16297               continue;
16298             }
16299             try {
16300               //allow all listeners attached to the current scope to run
16301               namedListeners[i].apply(null, listenerArgs);
16302             } catch (e) {
16303               $exceptionHandler(e);
16304             }
16305           }
16306           //if any listener on the current scope stops propagation, prevent bubbling
16307           if (stopPropagation) {
16308             event.currentScope = null;
16309             return event;
16310           }
16311           //traverse upwards
16312           scope = scope.$parent;
16313         } while (scope);
16314
16315         event.currentScope = null;
16316
16317         return event;
16318       },
16319
16320
16321       /**
16322        * @ngdoc method
16323        * @name $rootScope.Scope#$broadcast
16324        * @kind function
16325        *
16326        * @description
16327        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
16328        * registered {@link ng.$rootScope.Scope#$on} listeners.
16329        *
16330        * The event life cycle starts at the scope on which `$broadcast` was called. All
16331        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16332        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
16333        * scope and calls all registered listeners along the way. The event cannot be canceled.
16334        *
16335        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16336        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16337        *
16338        * @param {string} name Event name to broadcast.
16339        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16340        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
16341        */
16342       $broadcast: function(name, args) {
16343         var target = this,
16344             current = target,
16345             next = target,
16346             event = {
16347               name: name,
16348               targetScope: target,
16349               preventDefault: function() {
16350                 event.defaultPrevented = true;
16351               },
16352               defaultPrevented: false
16353             };
16354
16355         if (!target.$$listenerCount[name]) return event;
16356
16357         var listenerArgs = concat([event], arguments, 1),
16358             listeners, i, length;
16359
16360         //down while you can, then up and next sibling or up and next sibling until back at root
16361         while ((current = next)) {
16362           event.currentScope = current;
16363           listeners = current.$$listeners[name] || [];
16364           for (i = 0, length = listeners.length; i < length; i++) {
16365             // if listeners were deregistered, defragment the array
16366             if (!listeners[i]) {
16367               listeners.splice(i, 1);
16368               i--;
16369               length--;
16370               continue;
16371             }
16372
16373             try {
16374               listeners[i].apply(null, listenerArgs);
16375             } catch (e) {
16376               $exceptionHandler(e);
16377             }
16378           }
16379
16380           // Insanity Warning: scope depth-first traversal
16381           // yes, this code is a bit crazy, but it works and we have tests to prove it!
16382           // this piece should be kept in sync with the traversal in $digest
16383           // (though it differs due to having the extra check for $$listenerCount)
16384           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
16385               (current !== target && current.$$nextSibling)))) {
16386             while (current !== target && !(next = current.$$nextSibling)) {
16387               current = current.$parent;
16388             }
16389           }
16390         }
16391
16392         event.currentScope = null;
16393         return event;
16394       }
16395     };
16396
16397     var $rootScope = new Scope();
16398
16399     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
16400     var asyncQueue = $rootScope.$$asyncQueue = [];
16401     var postDigestQueue = $rootScope.$$postDigestQueue = [];
16402     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
16403
16404     return $rootScope;
16405
16406
16407     function beginPhase(phase) {
16408       if ($rootScope.$$phase) {
16409         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
16410       }
16411
16412       $rootScope.$$phase = phase;
16413     }
16414
16415     function clearPhase() {
16416       $rootScope.$$phase = null;
16417     }
16418
16419     function incrementWatchersCount(current, count) {
16420       do {
16421         current.$$watchersCount += count;
16422       } while ((current = current.$parent));
16423     }
16424
16425     function decrementListenerCount(current, count, name) {
16426       do {
16427         current.$$listenerCount[name] -= count;
16428
16429         if (current.$$listenerCount[name] === 0) {
16430           delete current.$$listenerCount[name];
16431         }
16432       } while ((current = current.$parent));
16433     }
16434
16435     /**
16436      * function used as an initial value for watchers.
16437      * because it's unique we can easily tell it apart from other values
16438      */
16439     function initWatchVal() {}
16440
16441     function flushApplyAsync() {
16442       while (applyAsyncQueue.length) {
16443         try {
16444           applyAsyncQueue.shift()();
16445         } catch (e) {
16446           $exceptionHandler(e);
16447         }
16448       }
16449       applyAsyncId = null;
16450     }
16451
16452     function scheduleApplyAsync() {
16453       if (applyAsyncId === null) {
16454         applyAsyncId = $browser.defer(function() {
16455           $rootScope.$apply(flushApplyAsync);
16456         });
16457       }
16458     }
16459   }];
16460 }
16461
16462 /**
16463  * @description
16464  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
16465  */
16466 function $$SanitizeUriProvider() {
16467   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
16468     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
16469
16470   /**
16471    * @description
16472    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16473    * urls during a[href] sanitization.
16474    *
16475    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16476    *
16477    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16478    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16479    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16480    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16481    *
16482    * @param {RegExp=} regexp New regexp to whitelist urls with.
16483    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16484    *    chaining otherwise.
16485    */
16486   this.aHrefSanitizationWhitelist = function(regexp) {
16487     if (isDefined(regexp)) {
16488       aHrefSanitizationWhitelist = regexp;
16489       return this;
16490     }
16491     return aHrefSanitizationWhitelist;
16492   };
16493
16494
16495   /**
16496    * @description
16497    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16498    * urls during img[src] sanitization.
16499    *
16500    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16501    *
16502    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16503    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16504    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16505    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16506    *
16507    * @param {RegExp=} regexp New regexp to whitelist urls with.
16508    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16509    *    chaining otherwise.
16510    */
16511   this.imgSrcSanitizationWhitelist = function(regexp) {
16512     if (isDefined(regexp)) {
16513       imgSrcSanitizationWhitelist = regexp;
16514       return this;
16515     }
16516     return imgSrcSanitizationWhitelist;
16517   };
16518
16519   this.$get = function() {
16520     return function sanitizeUri(uri, isImage) {
16521       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
16522       var normalizedVal;
16523       normalizedVal = urlResolve(uri).href;
16524       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
16525         return 'unsafe:' + normalizedVal;
16526       }
16527       return uri;
16528     };
16529   };
16530 }
16531
16532 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16533  *     Any commits to this file should be reviewed with security in mind.  *
16534  *   Changes to this file can potentially create security vulnerabilities. *
16535  *          An approval from 2 Core members with history of modifying      *
16536  *                         this file is required.                          *
16537  *                                                                         *
16538  *  Does the change somehow allow for arbitrary javascript to be executed? *
16539  *    Or allows for someone to change the prototype of built-in objects?   *
16540  *     Or gives undesired access to variables likes document or window?    *
16541  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16542
16543 var $sceMinErr = minErr('$sce');
16544
16545 var SCE_CONTEXTS = {
16546   HTML: 'html',
16547   CSS: 'css',
16548   URL: 'url',
16549   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
16550   // url.  (e.g. ng-include, script src, templateUrl)
16551   RESOURCE_URL: 'resourceUrl',
16552   JS: 'js'
16553 };
16554
16555 // Helper functions follow.
16556
16557 function adjustMatcher(matcher) {
16558   if (matcher === 'self') {
16559     return matcher;
16560   } else if (isString(matcher)) {
16561     // Strings match exactly except for 2 wildcards - '*' and '**'.
16562     // '*' matches any character except those from the set ':/.?&'.
16563     // '**' matches any character (like .* in a RegExp).
16564     // More than 2 *'s raises an error as it's ill defined.
16565     if (matcher.indexOf('***') > -1) {
16566       throw $sceMinErr('iwcard',
16567           'Illegal sequence *** in string matcher.  String: {0}', matcher);
16568     }
16569     matcher = escapeForRegexp(matcher).
16570                   replace('\\*\\*', '.*').
16571                   replace('\\*', '[^:/.?&;]*');
16572     return new RegExp('^' + matcher + '$');
16573   } else if (isRegExp(matcher)) {
16574     // The only other type of matcher allowed is a Regexp.
16575     // Match entire URL / disallow partial matches.
16576     // Flags are reset (i.e. no global, ignoreCase or multiline)
16577     return new RegExp('^' + matcher.source + '$');
16578   } else {
16579     throw $sceMinErr('imatcher',
16580         'Matchers may only be "self", string patterns or RegExp objects');
16581   }
16582 }
16583
16584
16585 function adjustMatchers(matchers) {
16586   var adjustedMatchers = [];
16587   if (isDefined(matchers)) {
16588     forEach(matchers, function(matcher) {
16589       adjustedMatchers.push(adjustMatcher(matcher));
16590     });
16591   }
16592   return adjustedMatchers;
16593 }
16594
16595
16596 /**
16597  * @ngdoc service
16598  * @name $sceDelegate
16599  * @kind function
16600  *
16601  * @description
16602  *
16603  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
16604  * Contextual Escaping (SCE)} services to AngularJS.
16605  *
16606  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
16607  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
16608  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
16609  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
16610  * work because `$sce` delegates to `$sceDelegate` for these operations.
16611  *
16612  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
16613  *
16614  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
16615  * can override it completely to change the behavior of `$sce`, the common case would
16616  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
16617  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
16618  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
16619  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
16620  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16621  */
16622
16623 /**
16624  * @ngdoc provider
16625  * @name $sceDelegateProvider
16626  * @description
16627  *
16628  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
16629  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
16630  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
16631  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
16632  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16633  *
16634  * For the general details about this service in Angular, read the main page for {@link ng.$sce
16635  * Strict Contextual Escaping (SCE)}.
16636  *
16637  * **Example**:  Consider the following case. <a name="example"></a>
16638  *
16639  * - your app is hosted at url `http://myapp.example.com/`
16640  * - but some of your templates are hosted on other domains you control such as
16641  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
16642  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
16643  *
16644  * Here is what a secure configuration for this scenario might look like:
16645  *
16646  * ```
16647  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
16648  *    $sceDelegateProvider.resourceUrlWhitelist([
16649  *      // Allow same origin resource loads.
16650  *      'self',
16651  *      // Allow loading from our assets domain.  Notice the difference between * and **.
16652  *      'http://srv*.assets.example.com/**'
16653  *    ]);
16654  *
16655  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
16656  *    $sceDelegateProvider.resourceUrlBlacklist([
16657  *      'http://myapp.example.com/clickThru**'
16658  *    ]);
16659  *  });
16660  * ```
16661  */
16662
16663 function $SceDelegateProvider() {
16664   this.SCE_CONTEXTS = SCE_CONTEXTS;
16665
16666   // Resource URLs can also be trusted by policy.
16667   var resourceUrlWhitelist = ['self'],
16668       resourceUrlBlacklist = [];
16669
16670   /**
16671    * @ngdoc method
16672    * @name $sceDelegateProvider#resourceUrlWhitelist
16673    * @kind function
16674    *
16675    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16676    *     provided.  This must be an array or null.  A snapshot of this array is used so further
16677    *     changes to the array are ignored.
16678    *
16679    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16680    *     allowed in this array.
16681    *
16682    *     Note: **an empty whitelist array will block all URLs**!
16683    *
16684    * @return {Array} the currently set whitelist array.
16685    *
16686    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
16687    * same origin resource requests.
16688    *
16689    * @description
16690    * Sets/Gets the whitelist of trusted resource URLs.
16691    */
16692   this.resourceUrlWhitelist = function(value) {
16693     if (arguments.length) {
16694       resourceUrlWhitelist = adjustMatchers(value);
16695     }
16696     return resourceUrlWhitelist;
16697   };
16698
16699   /**
16700    * @ngdoc method
16701    * @name $sceDelegateProvider#resourceUrlBlacklist
16702    * @kind function
16703    *
16704    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16705    *     provided.  This must be an array or null.  A snapshot of this array is used so further
16706    *     changes to the array are ignored.
16707    *
16708    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16709    *     allowed in this array.
16710    *
16711    *     The typical usage for the blacklist is to **block
16712    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16713    *     these would otherwise be trusted but actually return content from the redirected domain.
16714    *
16715    *     Finally, **the blacklist overrides the whitelist** and has the final say.
16716    *
16717    * @return {Array} the currently set blacklist array.
16718    *
16719    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
16720    * is no blacklist.)
16721    *
16722    * @description
16723    * Sets/Gets the blacklist of trusted resource URLs.
16724    */
16725
16726   this.resourceUrlBlacklist = function(value) {
16727     if (arguments.length) {
16728       resourceUrlBlacklist = adjustMatchers(value);
16729     }
16730     return resourceUrlBlacklist;
16731   };
16732
16733   this.$get = ['$injector', function($injector) {
16734
16735     var htmlSanitizer = function htmlSanitizer(html) {
16736       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16737     };
16738
16739     if ($injector.has('$sanitize')) {
16740       htmlSanitizer = $injector.get('$sanitize');
16741     }
16742
16743
16744     function matchUrl(matcher, parsedUrl) {
16745       if (matcher === 'self') {
16746         return urlIsSameOrigin(parsedUrl);
16747       } else {
16748         // definitely a regex.  See adjustMatchers()
16749         return !!matcher.exec(parsedUrl.href);
16750       }
16751     }
16752
16753     function isResourceUrlAllowedByPolicy(url) {
16754       var parsedUrl = urlResolve(url.toString());
16755       var i, n, allowed = false;
16756       // Ensure that at least one item from the whitelist allows this url.
16757       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
16758         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
16759           allowed = true;
16760           break;
16761         }
16762       }
16763       if (allowed) {
16764         // Ensure that no item from the blacklist blocked this url.
16765         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
16766           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
16767             allowed = false;
16768             break;
16769           }
16770         }
16771       }
16772       return allowed;
16773     }
16774
16775     function generateHolderType(Base) {
16776       var holderType = function TrustedValueHolderType(trustedValue) {
16777         this.$$unwrapTrustedValue = function() {
16778           return trustedValue;
16779         };
16780       };
16781       if (Base) {
16782         holderType.prototype = new Base();
16783       }
16784       holderType.prototype.valueOf = function sceValueOf() {
16785         return this.$$unwrapTrustedValue();
16786       };
16787       holderType.prototype.toString = function sceToString() {
16788         return this.$$unwrapTrustedValue().toString();
16789       };
16790       return holderType;
16791     }
16792
16793     var trustedValueHolderBase = generateHolderType(),
16794         byType = {};
16795
16796     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
16797     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
16798     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
16799     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
16800     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
16801
16802     /**
16803      * @ngdoc method
16804      * @name $sceDelegate#trustAs
16805      *
16806      * @description
16807      * Returns an object that is trusted by angular for use in specified strict
16808      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
16809      * attribute interpolation, any dom event binding attribute interpolation
16810      * such as for onclick,  etc.) that uses the provided value.
16811      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
16812      *
16813      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
16814      *   resourceUrl, html, js and css.
16815      * @param {*} value The value that that should be considered trusted/safe.
16816      * @returns {*} A value that can be used to stand in for the provided `value` in places
16817      * where Angular expects a $sce.trustAs() return value.
16818      */
16819     function trustAs(type, trustedValue) {
16820       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16821       if (!Constructor) {
16822         throw $sceMinErr('icontext',
16823             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
16824             type, trustedValue);
16825       }
16826       if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
16827         return trustedValue;
16828       }
16829       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
16830       // mutable objects, we ensure here that the value passed in is actually a string.
16831       if (typeof trustedValue !== 'string') {
16832         throw $sceMinErr('itype',
16833             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
16834             type);
16835       }
16836       return new Constructor(trustedValue);
16837     }
16838
16839     /**
16840      * @ngdoc method
16841      * @name $sceDelegate#valueOf
16842      *
16843      * @description
16844      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
16845      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
16846      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
16847      *
16848      * If the passed parameter is not a value that had been returned by {@link
16849      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
16850      *
16851      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
16852      *      call or anything else.
16853      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
16854      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
16855      *     `value` unchanged.
16856      */
16857     function valueOf(maybeTrusted) {
16858       if (maybeTrusted instanceof trustedValueHolderBase) {
16859         return maybeTrusted.$$unwrapTrustedValue();
16860       } else {
16861         return maybeTrusted;
16862       }
16863     }
16864
16865     /**
16866      * @ngdoc method
16867      * @name $sceDelegate#getTrusted
16868      *
16869      * @description
16870      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
16871      * returns the originally supplied value if the queried context type is a supertype of the
16872      * created type.  If this condition isn't satisfied, throws an exception.
16873      *
16874      * @param {string} type The kind of context in which this value is to be used.
16875      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16876      *     `$sceDelegate.trustAs`} call.
16877      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
16878      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
16879      */
16880     function getTrusted(type, maybeTrusted) {
16881       if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
16882         return maybeTrusted;
16883       }
16884       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16885       if (constructor && maybeTrusted instanceof constructor) {
16886         return maybeTrusted.$$unwrapTrustedValue();
16887       }
16888       // If we get here, then we may only take one of two actions.
16889       // 1. sanitize the value for the requested type, or
16890       // 2. throw an exception.
16891       if (type === SCE_CONTEXTS.RESOURCE_URL) {
16892         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
16893           return maybeTrusted;
16894         } else {
16895           throw $sceMinErr('insecurl',
16896               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
16897               maybeTrusted.toString());
16898         }
16899       } else if (type === SCE_CONTEXTS.HTML) {
16900         return htmlSanitizer(maybeTrusted);
16901       }
16902       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16903     }
16904
16905     return { trustAs: trustAs,
16906              getTrusted: getTrusted,
16907              valueOf: valueOf };
16908   }];
16909 }
16910
16911
16912 /**
16913  * @ngdoc provider
16914  * @name $sceProvider
16915  * @description
16916  *
16917  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
16918  * -   enable/disable Strict Contextual Escaping (SCE) in a module
16919  * -   override the default implementation with a custom delegate
16920  *
16921  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
16922  */
16923
16924 /* jshint maxlen: false*/
16925
16926 /**
16927  * @ngdoc service
16928  * @name $sce
16929  * @kind function
16930  *
16931  * @description
16932  *
16933  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
16934  *
16935  * # Strict Contextual Escaping
16936  *
16937  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
16938  * contexts to result in a value that is marked as safe to use for that context.  One example of
16939  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
16940  * to these contexts as privileged or SCE contexts.
16941  *
16942  * As of version 1.2, Angular ships with SCE enabled by default.
16943  *
16944  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
16945  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
16946  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
16947  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
16948  * to the top of your HTML document.
16949  *
16950  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
16951  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
16952  *
16953  * Here's an example of a binding in a privileged context:
16954  *
16955  * ```
16956  * <input ng-model="userHtml" aria-label="User input">
16957  * <div ng-bind-html="userHtml"></div>
16958  * ```
16959  *
16960  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
16961  * disabled, this application allows the user to render arbitrary HTML into the DIV.
16962  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
16963  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
16964  * security vulnerabilities.)
16965  *
16966  * For the case of HTML, you might use a library, either on the client side, or on the server side,
16967  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
16968  *
16969  * How would you ensure that every place that used these types of bindings was bound to a value that
16970  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
16971  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
16972  * properties/fields and forgot to update the binding to the sanitized value?
16973  *
16974  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
16975  * determine that something explicitly says it's safe to use a value for binding in that
16976  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
16977  * for those values that you can easily tell are safe - because they were received from your server,
16978  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
16979  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
16980  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
16981  *
16982  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
16983  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
16984  * obtain values that will be accepted by SCE / privileged contexts.
16985  *
16986  *
16987  * ## How does it work?
16988  *
16989  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
16990  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
16991  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
16992  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
16993  *
16994  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
16995  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
16996  * simplified):
16997  *
16998  * ```
16999  * var ngBindHtmlDirective = ['$sce', function($sce) {
17000  *   return function(scope, element, attr) {
17001  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
17002  *       element.html(value || '');
17003  *     });
17004  *   };
17005  * }];
17006  * ```
17007  *
17008  * ## Impact on loading templates
17009  *
17010  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
17011  * `templateUrl`'s specified by {@link guide/directive directives}.
17012  *
17013  * By default, Angular only loads templates from the same domain and protocol as the application
17014  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
17015  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
17016  * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
17017  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
17018  *
17019  * *Please note*:
17020  * The browser's
17021  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
17022  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
17023  * policy apply in addition to this and may further restrict whether the template is successfully
17024  * loaded.  This means that without the right CORS policy, loading templates from a different domain
17025  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
17026  * browsers.
17027  *
17028  * ## This feels like too much overhead
17029  *
17030  * It's important to remember that SCE only applies to interpolation expressions.
17031  *
17032  * If your expressions are constant literals, they're automatically trusted and you don't need to
17033  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
17034  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
17035  *
17036  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
17037  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
17038  *
17039  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
17040  * templates in `ng-include` from your application's domain without having to even know about SCE.
17041  * It blocks loading templates from other domains or loading templates over http from an https
17042  * served document.  You can change these by setting your own custom {@link
17043  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
17044  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
17045  *
17046  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
17047  * application that's secure and can be audited to verify that with much more ease than bolting
17048  * security onto an application later.
17049  *
17050  * <a name="contexts"></a>
17051  * ## What trusted context types are supported?
17052  *
17053  * | Context             | Notes          |
17054  * |---------------------|----------------|
17055  * | `$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. |
17056  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
17057  * | `$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. |
17058  * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
17059  * | `$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. |
17060  *
17061  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
17062  *
17063  *  Each element in these arrays must be one of the following:
17064  *
17065  *  - **'self'**
17066  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
17067  *      domain** as the application document using the **same protocol**.
17068  *  - **String** (except the special value `'self'`)
17069  *    - The string is matched against the full *normalized / absolute URL* of the resource
17070  *      being tested (substring matches are not good enough.)
17071  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
17072  *      match themselves.
17073  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
17074  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
17075  *      in a whitelist.
17076  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
17077  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
17078  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
17079  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
17080  *      http://foo.example.com/templates/**).
17081  *  - **RegExp** (*see caveat below*)
17082  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
17083  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
17084  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
17085  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
17086  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
17087  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
17088  *      is highly recommended to use the string patterns and only fall back to regular expressions
17089  *      as a last resort.
17090  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
17091  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
17092  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
17093  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
17094  *    - If you are generating your JavaScript from some other templating engine (not
17095  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
17096  *      remember to escape your regular expression (and be aware that you might need more than
17097  *      one level of escaping depending on your templating engine and the way you interpolated
17098  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
17099  *      enough before coding your own.  E.g. Ruby has
17100  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
17101  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
17102  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
17103  *      Closure library's [goog.string.regExpEscape(s)](
17104  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
17105  *
17106  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
17107  *
17108  * ## Show me an example using SCE.
17109  *
17110  * <example module="mySceApp" deps="angular-sanitize.js">
17111  * <file name="index.html">
17112  *   <div ng-controller="AppController as myCtrl">
17113  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
17114  *     <b>User comments</b><br>
17115  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
17116  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
17117  *     exploit.
17118  *     <div class="well">
17119  *       <div ng-repeat="userComment in myCtrl.userComments">
17120  *         <b>{{userComment.name}}</b>:
17121  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
17122  *         <br>
17123  *       </div>
17124  *     </div>
17125  *   </div>
17126  * </file>
17127  *
17128  * <file name="script.js">
17129  *   angular.module('mySceApp', ['ngSanitize'])
17130  *     .controller('AppController', ['$http', '$templateCache', '$sce',
17131  *       function($http, $templateCache, $sce) {
17132  *         var self = this;
17133  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
17134  *           self.userComments = userComments;
17135  *         });
17136  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
17137  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17138  *             'sanitization.&quot;">Hover over this text.</span>');
17139  *       }]);
17140  * </file>
17141  *
17142  * <file name="test_data.json">
17143  * [
17144  *   { "name": "Alice",
17145  *     "htmlComment":
17146  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
17147  *   },
17148  *   { "name": "Bob",
17149  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
17150  *   }
17151  * ]
17152  * </file>
17153  *
17154  * <file name="protractor.js" type="protractor">
17155  *   describe('SCE doc demo', function() {
17156  *     it('should sanitize untrusted values', function() {
17157  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
17158  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
17159  *     });
17160  *
17161  *     it('should NOT sanitize explicitly trusted values', function() {
17162  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
17163  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17164  *           'sanitization.&quot;">Hover over this text.</span>');
17165  *     });
17166  *   });
17167  * </file>
17168  * </example>
17169  *
17170  *
17171  *
17172  * ## Can I disable SCE completely?
17173  *
17174  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
17175  * for little coding overhead.  It will be much harder to take an SCE disabled application and
17176  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
17177  * for cases where you have a lot of existing code that was written before SCE was introduced and
17178  * you're migrating them a module at a time.
17179  *
17180  * That said, here's how you can completely disable SCE:
17181  *
17182  * ```
17183  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
17184  *   // Completely disable SCE.  For demonstration purposes only!
17185  *   // Do not use in new projects.
17186  *   $sceProvider.enabled(false);
17187  * });
17188  * ```
17189  *
17190  */
17191 /* jshint maxlen: 100 */
17192
17193 function $SceProvider() {
17194   var enabled = true;
17195
17196   /**
17197    * @ngdoc method
17198    * @name $sceProvider#enabled
17199    * @kind function
17200    *
17201    * @param {boolean=} value If provided, then enables/disables SCE.
17202    * @return {boolean} true if SCE is enabled, false otherwise.
17203    *
17204    * @description
17205    * Enables/disables SCE and returns the current value.
17206    */
17207   this.enabled = function(value) {
17208     if (arguments.length) {
17209       enabled = !!value;
17210     }
17211     return enabled;
17212   };
17213
17214
17215   /* Design notes on the default implementation for SCE.
17216    *
17217    * The API contract for the SCE delegate
17218    * -------------------------------------
17219    * The SCE delegate object must provide the following 3 methods:
17220    *
17221    * - trustAs(contextEnum, value)
17222    *     This method is used to tell the SCE service that the provided value is OK to use in the
17223    *     contexts specified by contextEnum.  It must return an object that will be accepted by
17224    *     getTrusted() for a compatible contextEnum and return this value.
17225    *
17226    * - valueOf(value)
17227    *     For values that were not produced by trustAs(), return them as is.  For values that were
17228    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
17229    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
17230    *     such a value.
17231    *
17232    * - getTrusted(contextEnum, value)
17233    *     This function should return the a value that is safe to use in the context specified by
17234    *     contextEnum or throw and exception otherwise.
17235    *
17236    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
17237    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
17238    * instance, an implementation could maintain a registry of all trusted objects by context.  In
17239    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
17240    * return the same object passed in if it was found in the registry under a compatible context or
17241    * throw an exception otherwise.  An implementation might only wrap values some of the time based
17242    * on some criteria.  getTrusted() might return a value and not throw an exception for special
17243    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
17244    *
17245    *
17246    * A note on the inheritance model for SCE contexts
17247    * ------------------------------------------------
17248    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
17249    * is purely an implementation details.
17250    *
17251    * The contract is simply this:
17252    *
17253    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
17254    *     will also succeed.
17255    *
17256    * Inheritance happens to capture this in a natural way.  In some future, we
17257    * may not use inheritance anymore.  That is OK because no code outside of
17258    * sce.js and sceSpecs.js would need to be aware of this detail.
17259    */
17260
17261   this.$get = ['$parse', '$sceDelegate', function(
17262                 $parse,   $sceDelegate) {
17263     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
17264     // the "expression(javascript expression)" syntax which is insecure.
17265     if (enabled && msie < 8) {
17266       throw $sceMinErr('iequirks',
17267         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
17268         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
17269         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
17270     }
17271
17272     var sce = shallowCopy(SCE_CONTEXTS);
17273
17274     /**
17275      * @ngdoc method
17276      * @name $sce#isEnabled
17277      * @kind function
17278      *
17279      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
17280      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
17281      *
17282      * @description
17283      * Returns a boolean indicating if SCE is enabled.
17284      */
17285     sce.isEnabled = function() {
17286       return enabled;
17287     };
17288     sce.trustAs = $sceDelegate.trustAs;
17289     sce.getTrusted = $sceDelegate.getTrusted;
17290     sce.valueOf = $sceDelegate.valueOf;
17291
17292     if (!enabled) {
17293       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
17294       sce.valueOf = identity;
17295     }
17296
17297     /**
17298      * @ngdoc method
17299      * @name $sce#parseAs
17300      *
17301      * @description
17302      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
17303      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
17304      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
17305      * *result*)}
17306      *
17307      * @param {string} type The kind of SCE context in which this result will be used.
17308      * @param {string} expression String expression to compile.
17309      * @returns {function(context, locals)} a function which represents the compiled expression:
17310      *
17311      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17312      *      are evaluated against (typically a scope object).
17313      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17314      *      `context`.
17315      */
17316     sce.parseAs = function sceParseAs(type, expr) {
17317       var parsed = $parse(expr);
17318       if (parsed.literal && parsed.constant) {
17319         return parsed;
17320       } else {
17321         return $parse(expr, function(value) {
17322           return sce.getTrusted(type, value);
17323         });
17324       }
17325     };
17326
17327     /**
17328      * @ngdoc method
17329      * @name $sce#trustAs
17330      *
17331      * @description
17332      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
17333      * returns an object that is trusted by angular for use in specified strict contextual
17334      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
17335      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
17336      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
17337      * escaping.
17338      *
17339      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
17340      *   resourceUrl, html, js and css.
17341      * @param {*} value The value that that should be considered trusted/safe.
17342      * @returns {*} A value that can be used to stand in for the provided `value` in places
17343      * where Angular expects a $sce.trustAs() return value.
17344      */
17345
17346     /**
17347      * @ngdoc method
17348      * @name $sce#trustAsHtml
17349      *
17350      * @description
17351      * Shorthand method.  `$sce.trustAsHtml(value)` →
17352      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
17353      *
17354      * @param {*} value The value to trustAs.
17355      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
17356      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
17357      *     only accept expressions that are either literal constants or are the
17358      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17359      */
17360
17361     /**
17362      * @ngdoc method
17363      * @name $sce#trustAsUrl
17364      *
17365      * @description
17366      * Shorthand method.  `$sce.trustAsUrl(value)` →
17367      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
17368      *
17369      * @param {*} value The value to trustAs.
17370      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
17371      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
17372      *     only accept expressions that are either literal constants or are the
17373      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17374      */
17375
17376     /**
17377      * @ngdoc method
17378      * @name $sce#trustAsResourceUrl
17379      *
17380      * @description
17381      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
17382      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
17383      *
17384      * @param {*} value The value to trustAs.
17385      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
17386      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
17387      *     only accept expressions that are either literal constants or are the return
17388      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
17389      */
17390
17391     /**
17392      * @ngdoc method
17393      * @name $sce#trustAsJs
17394      *
17395      * @description
17396      * Shorthand method.  `$sce.trustAsJs(value)` →
17397      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
17398      *
17399      * @param {*} value The value to trustAs.
17400      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
17401      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
17402      *     only accept expressions that are either literal constants or are the
17403      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17404      */
17405
17406     /**
17407      * @ngdoc method
17408      * @name $sce#getTrusted
17409      *
17410      * @description
17411      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
17412      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
17413      * originally supplied value if the queried context type is a supertype of the created type.
17414      * If this condition isn't satisfied, throws an exception.
17415      *
17416      * @param {string} type The kind of context in which this value is to be used.
17417      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
17418      *                         call.
17419      * @returns {*} The value the was originally provided to
17420      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
17421      *              Otherwise, throws an exception.
17422      */
17423
17424     /**
17425      * @ngdoc method
17426      * @name $sce#getTrustedHtml
17427      *
17428      * @description
17429      * Shorthand method.  `$sce.getTrustedHtml(value)` →
17430      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
17431      *
17432      * @param {*} value The value to pass to `$sce.getTrusted`.
17433      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
17434      */
17435
17436     /**
17437      * @ngdoc method
17438      * @name $sce#getTrustedCss
17439      *
17440      * @description
17441      * Shorthand method.  `$sce.getTrustedCss(value)` →
17442      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
17443      *
17444      * @param {*} value The value to pass to `$sce.getTrusted`.
17445      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
17446      */
17447
17448     /**
17449      * @ngdoc method
17450      * @name $sce#getTrustedUrl
17451      *
17452      * @description
17453      * Shorthand method.  `$sce.getTrustedUrl(value)` →
17454      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
17455      *
17456      * @param {*} value The value to pass to `$sce.getTrusted`.
17457      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
17458      */
17459
17460     /**
17461      * @ngdoc method
17462      * @name $sce#getTrustedResourceUrl
17463      *
17464      * @description
17465      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
17466      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
17467      *
17468      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
17469      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
17470      */
17471
17472     /**
17473      * @ngdoc method
17474      * @name $sce#getTrustedJs
17475      *
17476      * @description
17477      * Shorthand method.  `$sce.getTrustedJs(value)` →
17478      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
17479      *
17480      * @param {*} value The value to pass to `$sce.getTrusted`.
17481      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
17482      */
17483
17484     /**
17485      * @ngdoc method
17486      * @name $sce#parseAsHtml
17487      *
17488      * @description
17489      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
17490      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
17491      *
17492      * @param {string} expression String expression to compile.
17493      * @returns {function(context, locals)} a function which represents the compiled expression:
17494      *
17495      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17496      *      are evaluated against (typically a scope object).
17497      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17498      *      `context`.
17499      */
17500
17501     /**
17502      * @ngdoc method
17503      * @name $sce#parseAsCss
17504      *
17505      * @description
17506      * Shorthand method.  `$sce.parseAsCss(value)` →
17507      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
17508      *
17509      * @param {string} expression String expression to compile.
17510      * @returns {function(context, locals)} a function which represents the compiled expression:
17511      *
17512      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17513      *      are evaluated against (typically a scope object).
17514      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17515      *      `context`.
17516      */
17517
17518     /**
17519      * @ngdoc method
17520      * @name $sce#parseAsUrl
17521      *
17522      * @description
17523      * Shorthand method.  `$sce.parseAsUrl(value)` →
17524      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
17525      *
17526      * @param {string} expression String expression to compile.
17527      * @returns {function(context, locals)} a function which represents the compiled expression:
17528      *
17529      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17530      *      are evaluated against (typically a scope object).
17531      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17532      *      `context`.
17533      */
17534
17535     /**
17536      * @ngdoc method
17537      * @name $sce#parseAsResourceUrl
17538      *
17539      * @description
17540      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
17541      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
17542      *
17543      * @param {string} expression String expression to compile.
17544      * @returns {function(context, locals)} a function which represents the compiled expression:
17545      *
17546      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17547      *      are evaluated against (typically a scope object).
17548      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17549      *      `context`.
17550      */
17551
17552     /**
17553      * @ngdoc method
17554      * @name $sce#parseAsJs
17555      *
17556      * @description
17557      * Shorthand method.  `$sce.parseAsJs(value)` →
17558      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
17559      *
17560      * @param {string} expression String expression to compile.
17561      * @returns {function(context, locals)} a function which represents the compiled expression:
17562      *
17563      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17564      *      are evaluated against (typically a scope object).
17565      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17566      *      `context`.
17567      */
17568
17569     // Shorthand delegations.
17570     var parse = sce.parseAs,
17571         getTrusted = sce.getTrusted,
17572         trustAs = sce.trustAs;
17573
17574     forEach(SCE_CONTEXTS, function(enumValue, name) {
17575       var lName = lowercase(name);
17576       sce[camelCase("parse_as_" + lName)] = function(expr) {
17577         return parse(enumValue, expr);
17578       };
17579       sce[camelCase("get_trusted_" + lName)] = function(value) {
17580         return getTrusted(enumValue, value);
17581       };
17582       sce[camelCase("trust_as_" + lName)] = function(value) {
17583         return trustAs(enumValue, value);
17584       };
17585     });
17586
17587     return sce;
17588   }];
17589 }
17590
17591 /**
17592  * !!! This is an undocumented "private" service !!!
17593  *
17594  * @name $sniffer
17595  * @requires $window
17596  * @requires $document
17597  *
17598  * @property {boolean} history Does the browser support html5 history api ?
17599  * @property {boolean} transitions Does the browser support CSS transition events ?
17600  * @property {boolean} animations Does the browser support CSS animation events ?
17601  *
17602  * @description
17603  * This is very simple implementation of testing browser's features.
17604  */
17605 function $SnifferProvider() {
17606   this.$get = ['$window', '$document', function($window, $document) {
17607     var eventSupport = {},
17608         android =
17609           toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
17610         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
17611         document = $document[0] || {},
17612         vendorPrefix,
17613         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
17614         bodyStyle = document.body && document.body.style,
17615         transitions = false,
17616         animations = false,
17617         match;
17618
17619     if (bodyStyle) {
17620       for (var prop in bodyStyle) {
17621         if (match = vendorRegex.exec(prop)) {
17622           vendorPrefix = match[0];
17623           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
17624           break;
17625         }
17626       }
17627
17628       if (!vendorPrefix) {
17629         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
17630       }
17631
17632       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
17633       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
17634
17635       if (android && (!transitions ||  !animations)) {
17636         transitions = isString(bodyStyle.webkitTransition);
17637         animations = isString(bodyStyle.webkitAnimation);
17638       }
17639     }
17640
17641
17642     return {
17643       // Android has history.pushState, but it does not update location correctly
17644       // so let's not use the history API at all.
17645       // http://code.google.com/p/android/issues/detail?id=17471
17646       // https://github.com/angular/angular.js/issues/904
17647
17648       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
17649       // so let's not use the history API also
17650       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
17651       // jshint -W018
17652       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
17653       // jshint +W018
17654       hasEvent: function(event) {
17655         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
17656         // it. In particular the event is not fired when backspace or delete key are pressed or
17657         // when cut operation is performed.
17658         // IE10+ implements 'input' event but it erroneously fires under various situations,
17659         // e.g. when placeholder changes, or a form is focused.
17660         if (event === 'input' && msie <= 11) return false;
17661
17662         if (isUndefined(eventSupport[event])) {
17663           var divElm = document.createElement('div');
17664           eventSupport[event] = 'on' + event in divElm;
17665         }
17666
17667         return eventSupport[event];
17668       },
17669       csp: csp(),
17670       vendorPrefix: vendorPrefix,
17671       transitions: transitions,
17672       animations: animations,
17673       android: android
17674     };
17675   }];
17676 }
17677
17678 var $compileMinErr = minErr('$compile');
17679
17680 /**
17681  * @ngdoc service
17682  * @name $templateRequest
17683  *
17684  * @description
17685  * The `$templateRequest` service runs security checks then downloads the provided template using
17686  * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
17687  * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
17688  * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
17689  * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
17690  * when `tpl` is of type string and `$templateCache` has the matching entry.
17691  *
17692  * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
17693  * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
17694  *
17695  * @return {Promise} a promise for the HTTP response data of the given URL.
17696  *
17697  * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
17698  */
17699 function $TemplateRequestProvider() {
17700   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
17701     function handleRequestFn(tpl, ignoreRequestError) {
17702       handleRequestFn.totalPendingRequests++;
17703
17704       // We consider the template cache holds only trusted templates, so
17705       // there's no need to go through whitelisting again for keys that already
17706       // are included in there. This also makes Angular accept any script
17707       // directive, no matter its name. However, we still need to unwrap trusted
17708       // types.
17709       if (!isString(tpl) || !$templateCache.get(tpl)) {
17710         tpl = $sce.getTrustedResourceUrl(tpl);
17711       }
17712
17713       var transformResponse = $http.defaults && $http.defaults.transformResponse;
17714
17715       if (isArray(transformResponse)) {
17716         transformResponse = transformResponse.filter(function(transformer) {
17717           return transformer !== defaultHttpResponseTransform;
17718         });
17719       } else if (transformResponse === defaultHttpResponseTransform) {
17720         transformResponse = null;
17721       }
17722
17723       var httpOptions = {
17724         cache: $templateCache,
17725         transformResponse: transformResponse
17726       };
17727
17728       return $http.get(tpl, httpOptions)
17729         ['finally'](function() {
17730           handleRequestFn.totalPendingRequests--;
17731         })
17732         .then(function(response) {
17733           $templateCache.put(tpl, response.data);
17734           return response.data;
17735         }, handleError);
17736
17737       function handleError(resp) {
17738         if (!ignoreRequestError) {
17739           throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
17740             tpl, resp.status, resp.statusText);
17741         }
17742         return $q.reject(resp);
17743       }
17744     }
17745
17746     handleRequestFn.totalPendingRequests = 0;
17747
17748     return handleRequestFn;
17749   }];
17750 }
17751
17752 function $$TestabilityProvider() {
17753   this.$get = ['$rootScope', '$browser', '$location',
17754        function($rootScope,   $browser,   $location) {
17755
17756     /**
17757      * @name $testability
17758      *
17759      * @description
17760      * The private $$testability service provides a collection of methods for use when debugging
17761      * or by automated test and debugging tools.
17762      */
17763     var testability = {};
17764
17765     /**
17766      * @name $$testability#findBindings
17767      *
17768      * @description
17769      * Returns an array of elements that are bound (via ng-bind or {{}})
17770      * to expressions matching the input.
17771      *
17772      * @param {Element} element The element root to search from.
17773      * @param {string} expression The binding expression to match.
17774      * @param {boolean} opt_exactMatch If true, only returns exact matches
17775      *     for the expression. Filters and whitespace are ignored.
17776      */
17777     testability.findBindings = function(element, expression, opt_exactMatch) {
17778       var bindings = element.getElementsByClassName('ng-binding');
17779       var matches = [];
17780       forEach(bindings, function(binding) {
17781         var dataBinding = angular.element(binding).data('$binding');
17782         if (dataBinding) {
17783           forEach(dataBinding, function(bindingName) {
17784             if (opt_exactMatch) {
17785               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
17786               if (matcher.test(bindingName)) {
17787                 matches.push(binding);
17788               }
17789             } else {
17790               if (bindingName.indexOf(expression) != -1) {
17791                 matches.push(binding);
17792               }
17793             }
17794           });
17795         }
17796       });
17797       return matches;
17798     };
17799
17800     /**
17801      * @name $$testability#findModels
17802      *
17803      * @description
17804      * Returns an array of elements that are two-way found via ng-model to
17805      * expressions matching the input.
17806      *
17807      * @param {Element} element The element root to search from.
17808      * @param {string} expression The model expression to match.
17809      * @param {boolean} opt_exactMatch If true, only returns exact matches
17810      *     for the expression.
17811      */
17812     testability.findModels = function(element, expression, opt_exactMatch) {
17813       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
17814       for (var p = 0; p < prefixes.length; ++p) {
17815         var attributeEquals = opt_exactMatch ? '=' : '*=';
17816         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
17817         var elements = element.querySelectorAll(selector);
17818         if (elements.length) {
17819           return elements;
17820         }
17821       }
17822     };
17823
17824     /**
17825      * @name $$testability#getLocation
17826      *
17827      * @description
17828      * Shortcut for getting the location in a browser agnostic way. Returns
17829      *     the path, search, and hash. (e.g. /path?a=b#hash)
17830      */
17831     testability.getLocation = function() {
17832       return $location.url();
17833     };
17834
17835     /**
17836      * @name $$testability#setLocation
17837      *
17838      * @description
17839      * Shortcut for navigating to a location without doing a full page reload.
17840      *
17841      * @param {string} url The location url (path, search and hash,
17842      *     e.g. /path?a=b#hash) to go to.
17843      */
17844     testability.setLocation = function(url) {
17845       if (url !== $location.url()) {
17846         $location.url(url);
17847         $rootScope.$digest();
17848       }
17849     };
17850
17851     /**
17852      * @name $$testability#whenStable
17853      *
17854      * @description
17855      * Calls the callback when $timeout and $http requests are completed.
17856      *
17857      * @param {function} callback
17858      */
17859     testability.whenStable = function(callback) {
17860       $browser.notifyWhenNoOutstandingRequests(callback);
17861     };
17862
17863     return testability;
17864   }];
17865 }
17866
17867 function $TimeoutProvider() {
17868   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
17869        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
17870
17871     var deferreds = {};
17872
17873
17874      /**
17875       * @ngdoc service
17876       * @name $timeout
17877       *
17878       * @description
17879       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
17880       * block and delegates any exceptions to
17881       * {@link ng.$exceptionHandler $exceptionHandler} service.
17882       *
17883       * The return value of calling `$timeout` is a promise, which will be resolved when
17884       * the delay has passed and the timeout function, if provided, is executed.
17885       *
17886       * To cancel a timeout request, call `$timeout.cancel(promise)`.
17887       *
17888       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
17889       * synchronously flush the queue of deferred functions.
17890       *
17891       * If you only want a promise that will be resolved after some specified delay
17892       * then you can call `$timeout` without the `fn` function.
17893       *
17894       * @param {function()=} fn A function, whose execution should be delayed.
17895       * @param {number=} [delay=0] Delay in milliseconds.
17896       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17897       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17898       * @param {...*=} Pass additional parameters to the executed function.
17899       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17900       *   promise will be resolved with is the return value of the `fn` function.
17901       *
17902       */
17903     function timeout(fn, delay, invokeApply) {
17904       if (!isFunction(fn)) {
17905         invokeApply = delay;
17906         delay = fn;
17907         fn = noop;
17908       }
17909
17910       var args = sliceArgs(arguments, 3),
17911           skipApply = (isDefined(invokeApply) && !invokeApply),
17912           deferred = (skipApply ? $$q : $q).defer(),
17913           promise = deferred.promise,
17914           timeoutId;
17915
17916       timeoutId = $browser.defer(function() {
17917         try {
17918           deferred.resolve(fn.apply(null, args));
17919         } catch (e) {
17920           deferred.reject(e);
17921           $exceptionHandler(e);
17922         }
17923         finally {
17924           delete deferreds[promise.$$timeoutId];
17925         }
17926
17927         if (!skipApply) $rootScope.$apply();
17928       }, delay);
17929
17930       promise.$$timeoutId = timeoutId;
17931       deferreds[timeoutId] = deferred;
17932
17933       return promise;
17934     }
17935
17936
17937      /**
17938       * @ngdoc method
17939       * @name $timeout#cancel
17940       *
17941       * @description
17942       * Cancels a task associated with the `promise`. As a result of this, the promise will be
17943       * resolved with a rejection.
17944       *
17945       * @param {Promise=} promise Promise returned by the `$timeout` function.
17946       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
17947       *   canceled.
17948       */
17949     timeout.cancel = function(promise) {
17950       if (promise && promise.$$timeoutId in deferreds) {
17951         deferreds[promise.$$timeoutId].reject('canceled');
17952         delete deferreds[promise.$$timeoutId];
17953         return $browser.defer.cancel(promise.$$timeoutId);
17954       }
17955       return false;
17956     };
17957
17958     return timeout;
17959   }];
17960 }
17961
17962 // NOTE:  The usage of window and document instead of $window and $document here is
17963 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
17964 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
17965 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
17966 // doesn't know about mocked locations and resolves URLs to the real document - which is
17967 // exactly the behavior needed here.  There is little value is mocking these out for this
17968 // service.
17969 var urlParsingNode = document.createElement("a");
17970 var originUrl = urlResolve(window.location.href);
17971
17972
17973 /**
17974  *
17975  * Implementation Notes for non-IE browsers
17976  * ----------------------------------------
17977  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
17978  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
17979  * URL will be resolved into an absolute URL in the context of the application document.
17980  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
17981  * properties are all populated to reflect the normalized URL.  This approach has wide
17982  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
17983  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
17984  *
17985  * Implementation Notes for IE
17986  * ---------------------------
17987  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
17988  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
17989  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
17990  * work around that by performing the parsing in a 2nd step by taking a previously normalized
17991  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
17992  * properties such as protocol, hostname, port, etc.
17993  *
17994  * References:
17995  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
17996  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
17997  *   http://url.spec.whatwg.org/#urlutils
17998  *   https://github.com/angular/angular.js/pull/2902
17999  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
18000  *
18001  * @kind function
18002  * @param {string} url The URL to be parsed.
18003  * @description Normalizes and parses a URL.
18004  * @returns {object} Returns the normalized URL as a dictionary.
18005  *
18006  *   | member name   | Description    |
18007  *   |---------------|----------------|
18008  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
18009  *   | protocol      | The protocol including the trailing colon                              |
18010  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
18011  *   | search        | The search params, minus the question mark                             |
18012  *   | hash          | The hash string, minus the hash symbol
18013  *   | hostname      | The hostname
18014  *   | port          | The port, without ":"
18015  *   | pathname      | The pathname, beginning with "/"
18016  *
18017  */
18018 function urlResolve(url) {
18019   var href = url;
18020
18021   if (msie) {
18022     // Normalize before parse.  Refer Implementation Notes on why this is
18023     // done in two steps on IE.
18024     urlParsingNode.setAttribute("href", href);
18025     href = urlParsingNode.href;
18026   }
18027
18028   urlParsingNode.setAttribute('href', href);
18029
18030   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
18031   return {
18032     href: urlParsingNode.href,
18033     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
18034     host: urlParsingNode.host,
18035     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
18036     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
18037     hostname: urlParsingNode.hostname,
18038     port: urlParsingNode.port,
18039     pathname: (urlParsingNode.pathname.charAt(0) === '/')
18040       ? urlParsingNode.pathname
18041       : '/' + urlParsingNode.pathname
18042   };
18043 }
18044
18045 /**
18046  * Parse a request URL and determine whether this is a same-origin request as the application document.
18047  *
18048  * @param {string|object} requestUrl The url of the request as a string that will be resolved
18049  * or a parsed URL object.
18050  * @returns {boolean} Whether the request is for the same origin as the application document.
18051  */
18052 function urlIsSameOrigin(requestUrl) {
18053   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
18054   return (parsed.protocol === originUrl.protocol &&
18055           parsed.host === originUrl.host);
18056 }
18057
18058 /**
18059  * @ngdoc service
18060  * @name $window
18061  *
18062  * @description
18063  * A reference to the browser's `window` object. While `window`
18064  * is globally available in JavaScript, it causes testability problems, because
18065  * it is a global variable. In angular we always refer to it through the
18066  * `$window` service, so it may be overridden, removed or mocked for testing.
18067  *
18068  * Expressions, like the one defined for the `ngClick` directive in the example
18069  * below, are evaluated with respect to the current scope.  Therefore, there is
18070  * no risk of inadvertently coding in a dependency on a global value in such an
18071  * expression.
18072  *
18073  * @example
18074    <example module="windowExample">
18075      <file name="index.html">
18076        <script>
18077          angular.module('windowExample', [])
18078            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
18079              $scope.greeting = 'Hello, World!';
18080              $scope.doGreeting = function(greeting) {
18081                $window.alert(greeting);
18082              };
18083            }]);
18084        </script>
18085        <div ng-controller="ExampleController">
18086          <input type="text" ng-model="greeting" aria-label="greeting" />
18087          <button ng-click="doGreeting(greeting)">ALERT</button>
18088        </div>
18089      </file>
18090      <file name="protractor.js" type="protractor">
18091       it('should display the greeting in the input box', function() {
18092        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
18093        // If we click the button it will block the test runner
18094        // element(':button').click();
18095       });
18096      </file>
18097    </example>
18098  */
18099 function $WindowProvider() {
18100   this.$get = valueFn(window);
18101 }
18102
18103 /**
18104  * @name $$cookieReader
18105  * @requires $document
18106  *
18107  * @description
18108  * This is a private service for reading cookies used by $http and ngCookies
18109  *
18110  * @return {Object} a key/value map of the current cookies
18111  */
18112 function $$CookieReader($document) {
18113   var rawDocument = $document[0] || {};
18114   var lastCookies = {};
18115   var lastCookieString = '';
18116
18117   function safeDecodeURIComponent(str) {
18118     try {
18119       return decodeURIComponent(str);
18120     } catch (e) {
18121       return str;
18122     }
18123   }
18124
18125   return function() {
18126     var cookieArray, cookie, i, index, name;
18127     var currentCookieString = rawDocument.cookie || '';
18128
18129     if (currentCookieString !== lastCookieString) {
18130       lastCookieString = currentCookieString;
18131       cookieArray = lastCookieString.split('; ');
18132       lastCookies = {};
18133
18134       for (i = 0; i < cookieArray.length; i++) {
18135         cookie = cookieArray[i];
18136         index = cookie.indexOf('=');
18137         if (index > 0) { //ignore nameless cookies
18138           name = safeDecodeURIComponent(cookie.substring(0, index));
18139           // the first value that is seen for a cookie is the most
18140           // specific one.  values for the same cookie name that
18141           // follow are for less specific paths.
18142           if (isUndefined(lastCookies[name])) {
18143             lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
18144           }
18145         }
18146       }
18147     }
18148     return lastCookies;
18149   };
18150 }
18151
18152 $$CookieReader.$inject = ['$document'];
18153
18154 function $$CookieReaderProvider() {
18155   this.$get = $$CookieReader;
18156 }
18157
18158 /* global currencyFilter: true,
18159  dateFilter: true,
18160  filterFilter: true,
18161  jsonFilter: true,
18162  limitToFilter: true,
18163  lowercaseFilter: true,
18164  numberFilter: true,
18165  orderByFilter: true,
18166  uppercaseFilter: true,
18167  */
18168
18169 /**
18170  * @ngdoc provider
18171  * @name $filterProvider
18172  * @description
18173  *
18174  * Filters are just functions which transform input to an output. However filters need to be
18175  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
18176  * annotated with dependencies and is responsible for creating a filter function.
18177  *
18178  * <div class="alert alert-warning">
18179  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18180  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18181  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18182  * (`myapp_subsection_filterx`).
18183  * </div>
18184  *
18185  * ```js
18186  *   // Filter registration
18187  *   function MyModule($provide, $filterProvider) {
18188  *     // create a service to demonstrate injection (not always needed)
18189  *     $provide.value('greet', function(name){
18190  *       return 'Hello ' + name + '!';
18191  *     });
18192  *
18193  *     // register a filter factory which uses the
18194  *     // greet service to demonstrate DI.
18195  *     $filterProvider.register('greet', function(greet){
18196  *       // return the filter function which uses the greet service
18197  *       // to generate salutation
18198  *       return function(text) {
18199  *         // filters need to be forgiving so check input validity
18200  *         return text && greet(text) || text;
18201  *       };
18202  *     });
18203  *   }
18204  * ```
18205  *
18206  * The filter function is registered with the `$injector` under the filter name suffix with
18207  * `Filter`.
18208  *
18209  * ```js
18210  *   it('should be the same instance', inject(
18211  *     function($filterProvider) {
18212  *       $filterProvider.register('reverse', function(){
18213  *         return ...;
18214  *       });
18215  *     },
18216  *     function($filter, reverseFilter) {
18217  *       expect($filter('reverse')).toBe(reverseFilter);
18218  *     });
18219  * ```
18220  *
18221  *
18222  * For more information about how angular filters work, and how to create your own filters, see
18223  * {@link guide/filter Filters} in the Angular Developer Guide.
18224  */
18225
18226 /**
18227  * @ngdoc service
18228  * @name $filter
18229  * @kind function
18230  * @description
18231  * Filters are used for formatting data displayed to the user.
18232  *
18233  * The general syntax in templates is as follows:
18234  *
18235  *         {{ expression [| filter_name[:parameter_value] ... ] }}
18236  *
18237  * @param {String} name Name of the filter function to retrieve
18238  * @return {Function} the filter function
18239  * @example
18240    <example name="$filter" module="filterExample">
18241      <file name="index.html">
18242        <div ng-controller="MainCtrl">
18243         <h3>{{ originalText }}</h3>
18244         <h3>{{ filteredText }}</h3>
18245        </div>
18246      </file>
18247
18248      <file name="script.js">
18249       angular.module('filterExample', [])
18250       .controller('MainCtrl', function($scope, $filter) {
18251         $scope.originalText = 'hello';
18252         $scope.filteredText = $filter('uppercase')($scope.originalText);
18253       });
18254      </file>
18255    </example>
18256   */
18257 $FilterProvider.$inject = ['$provide'];
18258 function $FilterProvider($provide) {
18259   var suffix = 'Filter';
18260
18261   /**
18262    * @ngdoc method
18263    * @name $filterProvider#register
18264    * @param {string|Object} name Name of the filter function, or an object map of filters where
18265    *    the keys are the filter names and the values are the filter factories.
18266    *
18267    *    <div class="alert alert-warning">
18268    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18269    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18270    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18271    *    (`myapp_subsection_filterx`).
18272    *    </div>
18273     * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
18274    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
18275    *    of the registered filter instances.
18276    */
18277   function register(name, factory) {
18278     if (isObject(name)) {
18279       var filters = {};
18280       forEach(name, function(filter, key) {
18281         filters[key] = register(key, filter);
18282       });
18283       return filters;
18284     } else {
18285       return $provide.factory(name + suffix, factory);
18286     }
18287   }
18288   this.register = register;
18289
18290   this.$get = ['$injector', function($injector) {
18291     return function(name) {
18292       return $injector.get(name + suffix);
18293     };
18294   }];
18295
18296   ////////////////////////////////////////
18297
18298   /* global
18299     currencyFilter: false,
18300     dateFilter: false,
18301     filterFilter: false,
18302     jsonFilter: false,
18303     limitToFilter: false,
18304     lowercaseFilter: false,
18305     numberFilter: false,
18306     orderByFilter: false,
18307     uppercaseFilter: false,
18308   */
18309
18310   register('currency', currencyFilter);
18311   register('date', dateFilter);
18312   register('filter', filterFilter);
18313   register('json', jsonFilter);
18314   register('limitTo', limitToFilter);
18315   register('lowercase', lowercaseFilter);
18316   register('number', numberFilter);
18317   register('orderBy', orderByFilter);
18318   register('uppercase', uppercaseFilter);
18319 }
18320
18321 /**
18322  * @ngdoc filter
18323  * @name filter
18324  * @kind function
18325  *
18326  * @description
18327  * Selects a subset of items from `array` and returns it as a new array.
18328  *
18329  * @param {Array} array The source array.
18330  * @param {string|Object|function()} expression The predicate to be used for selecting items from
18331  *   `array`.
18332  *
18333  *   Can be one of:
18334  *
18335  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
18336  *     objects with string properties in `array` that match this string will be returned. This also
18337  *     applies to nested object properties.
18338  *     The predicate can be negated by prefixing the string with `!`.
18339  *
18340  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
18341  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
18342  *     which have property `name` containing "M" and property `phone` containing "1". A special
18343  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
18344  *     property of the object or its nested object properties. That's equivalent to the simple
18345  *     substring match with a `string` as described above. The predicate can be negated by prefixing
18346  *     the string with `!`.
18347  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
18348  *     not containing "M".
18349  *
18350  *     Note that a named property will match properties on the same level only, while the special
18351  *     `$` property will match properties on the same level or deeper. E.g. an array item like
18352  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
18353  *     **will** be matched by `{$: 'John'}`.
18354  *
18355  *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
18356  *     The function is called for each element of the array, with the element, its index, and
18357  *     the entire array itself as arguments.
18358  *
18359  *     The final result is an array of those elements that the predicate returned true for.
18360  *
18361  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
18362  *     determining if the expected value (from the filter expression) and actual value (from
18363  *     the object in the array) should be considered a match.
18364  *
18365  *   Can be one of:
18366  *
18367  *   - `function(actual, expected)`:
18368  *     The function will be given the object value and the predicate value to compare and
18369  *     should return true if both values should be considered equal.
18370  *
18371  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
18372  *     This is essentially strict comparison of expected and actual.
18373  *
18374  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
18375  *     insensitive way.
18376  *
18377  *     Primitive values are converted to strings. Objects are not compared against primitives,
18378  *     unless they have a custom `toString` method (e.g. `Date` objects).
18379  *
18380  * @example
18381    <example>
18382      <file name="index.html">
18383        <div ng-init="friends = [{name:'John', phone:'555-1276'},
18384                                 {name:'Mary', phone:'800-BIG-MARY'},
18385                                 {name:'Mike', phone:'555-4321'},
18386                                 {name:'Adam', phone:'555-5678'},
18387                                 {name:'Julie', phone:'555-8765'},
18388                                 {name:'Juliette', phone:'555-5678'}]"></div>
18389
18390        <label>Search: <input ng-model="searchText"></label>
18391        <table id="searchTextResults">
18392          <tr><th>Name</th><th>Phone</th></tr>
18393          <tr ng-repeat="friend in friends | filter:searchText">
18394            <td>{{friend.name}}</td>
18395            <td>{{friend.phone}}</td>
18396          </tr>
18397        </table>
18398        <hr>
18399        <label>Any: <input ng-model="search.$"></label> <br>
18400        <label>Name only <input ng-model="search.name"></label><br>
18401        <label>Phone only <input ng-model="search.phone"></label><br>
18402        <label>Equality <input type="checkbox" ng-model="strict"></label><br>
18403        <table id="searchObjResults">
18404          <tr><th>Name</th><th>Phone</th></tr>
18405          <tr ng-repeat="friendObj in friends | filter:search:strict">
18406            <td>{{friendObj.name}}</td>
18407            <td>{{friendObj.phone}}</td>
18408          </tr>
18409        </table>
18410      </file>
18411      <file name="protractor.js" type="protractor">
18412        var expectFriendNames = function(expectedNames, key) {
18413          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
18414            arr.forEach(function(wd, i) {
18415              expect(wd.getText()).toMatch(expectedNames[i]);
18416            });
18417          });
18418        };
18419
18420        it('should search across all fields when filtering with a string', function() {
18421          var searchText = element(by.model('searchText'));
18422          searchText.clear();
18423          searchText.sendKeys('m');
18424          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
18425
18426          searchText.clear();
18427          searchText.sendKeys('76');
18428          expectFriendNames(['John', 'Julie'], 'friend');
18429        });
18430
18431        it('should search in specific fields when filtering with a predicate object', function() {
18432          var searchAny = element(by.model('search.$'));
18433          searchAny.clear();
18434          searchAny.sendKeys('i');
18435          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
18436        });
18437        it('should use a equal comparison when comparator is true', function() {
18438          var searchName = element(by.model('search.name'));
18439          var strict = element(by.model('strict'));
18440          searchName.clear();
18441          searchName.sendKeys('Julie');
18442          strict.click();
18443          expectFriendNames(['Julie'], 'friendObj');
18444        });
18445      </file>
18446    </example>
18447  */
18448 function filterFilter() {
18449   return function(array, expression, comparator) {
18450     if (!isArrayLike(array)) {
18451       if (array == null) {
18452         return array;
18453       } else {
18454         throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
18455       }
18456     }
18457
18458     var expressionType = getTypeForFilter(expression);
18459     var predicateFn;
18460     var matchAgainstAnyProp;
18461
18462     switch (expressionType) {
18463       case 'function':
18464         predicateFn = expression;
18465         break;
18466       case 'boolean':
18467       case 'null':
18468       case 'number':
18469       case 'string':
18470         matchAgainstAnyProp = true;
18471         //jshint -W086
18472       case 'object':
18473         //jshint +W086
18474         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
18475         break;
18476       default:
18477         return array;
18478     }
18479
18480     return Array.prototype.filter.call(array, predicateFn);
18481   };
18482 }
18483
18484 // Helper functions for `filterFilter`
18485 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
18486   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
18487   var predicateFn;
18488
18489   if (comparator === true) {
18490     comparator = equals;
18491   } else if (!isFunction(comparator)) {
18492     comparator = function(actual, expected) {
18493       if (isUndefined(actual)) {
18494         // No substring matching against `undefined`
18495         return false;
18496       }
18497       if ((actual === null) || (expected === null)) {
18498         // No substring matching against `null`; only match against `null`
18499         return actual === expected;
18500       }
18501       if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
18502         // Should not compare primitives against objects, unless they have custom `toString` method
18503         return false;
18504       }
18505
18506       actual = lowercase('' + actual);
18507       expected = lowercase('' + expected);
18508       return actual.indexOf(expected) !== -1;
18509     };
18510   }
18511
18512   predicateFn = function(item) {
18513     if (shouldMatchPrimitives && !isObject(item)) {
18514       return deepCompare(item, expression.$, comparator, false);
18515     }
18516     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
18517   };
18518
18519   return predicateFn;
18520 }
18521
18522 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
18523   var actualType = getTypeForFilter(actual);
18524   var expectedType = getTypeForFilter(expected);
18525
18526   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
18527     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
18528   } else if (isArray(actual)) {
18529     // In case `actual` is an array, consider it a match
18530     // if ANY of it's items matches `expected`
18531     return actual.some(function(item) {
18532       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
18533     });
18534   }
18535
18536   switch (actualType) {
18537     case 'object':
18538       var key;
18539       if (matchAgainstAnyProp) {
18540         for (key in actual) {
18541           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
18542             return true;
18543           }
18544         }
18545         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
18546       } else if (expectedType === 'object') {
18547         for (key in expected) {
18548           var expectedVal = expected[key];
18549           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
18550             continue;
18551           }
18552
18553           var matchAnyProperty = key === '$';
18554           var actualVal = matchAnyProperty ? actual : actual[key];
18555           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
18556             return false;
18557           }
18558         }
18559         return true;
18560       } else {
18561         return comparator(actual, expected);
18562       }
18563       break;
18564     case 'function':
18565       return false;
18566     default:
18567       return comparator(actual, expected);
18568   }
18569 }
18570
18571 // Used for easily differentiating between `null` and actual `object`
18572 function getTypeForFilter(val) {
18573   return (val === null) ? 'null' : typeof val;
18574 }
18575
18576 /**
18577  * @ngdoc filter
18578  * @name currency
18579  * @kind function
18580  *
18581  * @description
18582  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
18583  * symbol for current locale is used.
18584  *
18585  * @param {number} amount Input to filter.
18586  * @param {string=} symbol Currency symbol or identifier to be displayed.
18587  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
18588  * @returns {string} Formatted number.
18589  *
18590  *
18591  * @example
18592    <example module="currencyExample">
18593      <file name="index.html">
18594        <script>
18595          angular.module('currencyExample', [])
18596            .controller('ExampleController', ['$scope', function($scope) {
18597              $scope.amount = 1234.56;
18598            }]);
18599        </script>
18600        <div ng-controller="ExampleController">
18601          <input type="number" ng-model="amount" aria-label="amount"> <br>
18602          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
18603          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
18604          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
18605        </div>
18606      </file>
18607      <file name="protractor.js" type="protractor">
18608        it('should init with 1234.56', function() {
18609          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
18610          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
18611          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
18612        });
18613        it('should update', function() {
18614          if (browser.params.browser == 'safari') {
18615            // Safari does not understand the minus key. See
18616            // https://github.com/angular/protractor/issues/481
18617            return;
18618          }
18619          element(by.model('amount')).clear();
18620          element(by.model('amount')).sendKeys('-1234');
18621          expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
18622          expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
18623          expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
18624        });
18625      </file>
18626    </example>
18627  */
18628 currencyFilter.$inject = ['$locale'];
18629 function currencyFilter($locale) {
18630   var formats = $locale.NUMBER_FORMATS;
18631   return function(amount, currencySymbol, fractionSize) {
18632     if (isUndefined(currencySymbol)) {
18633       currencySymbol = formats.CURRENCY_SYM;
18634     }
18635
18636     if (isUndefined(fractionSize)) {
18637       fractionSize = formats.PATTERNS[1].maxFrac;
18638     }
18639
18640     // if null or undefined pass it through
18641     return (amount == null)
18642         ? amount
18643         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
18644             replace(/\u00A4/g, currencySymbol);
18645   };
18646 }
18647
18648 /**
18649  * @ngdoc filter
18650  * @name number
18651  * @kind function
18652  *
18653  * @description
18654  * Formats a number as text.
18655  *
18656  * If the input is null or undefined, it will just be returned.
18657  * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
18658  * If the input is not a number an empty string is returned.
18659  *
18660  *
18661  * @param {number|string} number Number to format.
18662  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18663  * If this is not provided then the fraction size is computed from the current locale's number
18664  * formatting pattern. In the case of the default locale, it will be 3.
18665  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
18666  *
18667  * @example
18668    <example module="numberFilterExample">
18669      <file name="index.html">
18670        <script>
18671          angular.module('numberFilterExample', [])
18672            .controller('ExampleController', ['$scope', function($scope) {
18673              $scope.val = 1234.56789;
18674            }]);
18675        </script>
18676        <div ng-controller="ExampleController">
18677          <label>Enter number: <input ng-model='val'></label><br>
18678          Default formatting: <span id='number-default'>{{val | number}}</span><br>
18679          No fractions: <span>{{val | number:0}}</span><br>
18680          Negative number: <span>{{-val | number:4}}</span>
18681        </div>
18682      </file>
18683      <file name="protractor.js" type="protractor">
18684        it('should format numbers', function() {
18685          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
18686          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
18687          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
18688        });
18689
18690        it('should update', function() {
18691          element(by.model('val')).clear();
18692          element(by.model('val')).sendKeys('3374.333');
18693          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
18694          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
18695          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
18696       });
18697      </file>
18698    </example>
18699  */
18700
18701
18702 numberFilter.$inject = ['$locale'];
18703 function numberFilter($locale) {
18704   var formats = $locale.NUMBER_FORMATS;
18705   return function(number, fractionSize) {
18706
18707     // if null or undefined pass it through
18708     return (number == null)
18709         ? number
18710         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
18711                        fractionSize);
18712   };
18713 }
18714
18715 var DECIMAL_SEP = '.';
18716 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18717   if (isObject(number)) return '';
18718
18719   var isNegative = number < 0;
18720   number = Math.abs(number);
18721
18722   var isInfinity = number === Infinity;
18723   if (!isInfinity && !isFinite(number)) return '';
18724
18725   var numStr = number + '',
18726       formatedText = '',
18727       hasExponent = false,
18728       parts = [];
18729
18730   if (isInfinity) formatedText = '\u221e';
18731
18732   if (!isInfinity && numStr.indexOf('e') !== -1) {
18733     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18734     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18735       number = 0;
18736     } else {
18737       formatedText = numStr;
18738       hasExponent = true;
18739     }
18740   }
18741
18742   if (!isInfinity && !hasExponent) {
18743     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
18744
18745     // determine fractionSize if it is not specified
18746     if (isUndefined(fractionSize)) {
18747       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
18748     }
18749
18750     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18751     // inspired by:
18752     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18753     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
18754
18755     var fraction = ('' + number).split(DECIMAL_SEP);
18756     var whole = fraction[0];
18757     fraction = fraction[1] || '';
18758
18759     var i, pos = 0,
18760         lgroup = pattern.lgSize,
18761         group = pattern.gSize;
18762
18763     if (whole.length >= (lgroup + group)) {
18764       pos = whole.length - lgroup;
18765       for (i = 0; i < pos; i++) {
18766         if ((pos - i) % group === 0 && i !== 0) {
18767           formatedText += groupSep;
18768         }
18769         formatedText += whole.charAt(i);
18770       }
18771     }
18772
18773     for (i = pos; i < whole.length; i++) {
18774       if ((whole.length - i) % lgroup === 0 && i !== 0) {
18775         formatedText += groupSep;
18776       }
18777       formatedText += whole.charAt(i);
18778     }
18779
18780     // format fraction part.
18781     while (fraction.length < fractionSize) {
18782       fraction += '0';
18783     }
18784
18785     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18786   } else {
18787     if (fractionSize > 0 && number < 1) {
18788       formatedText = number.toFixed(fractionSize);
18789       number = parseFloat(formatedText);
18790       formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
18791     }
18792   }
18793
18794   if (number === 0) {
18795     isNegative = false;
18796   }
18797
18798   parts.push(isNegative ? pattern.negPre : pattern.posPre,
18799              formatedText,
18800              isNegative ? pattern.negSuf : pattern.posSuf);
18801   return parts.join('');
18802 }
18803
18804 function padNumber(num, digits, trim) {
18805   var neg = '';
18806   if (num < 0) {
18807     neg =  '-';
18808     num = -num;
18809   }
18810   num = '' + num;
18811   while (num.length < digits) num = '0' + num;
18812   if (trim) {
18813     num = num.substr(num.length - digits);
18814   }
18815   return neg + num;
18816 }
18817
18818
18819 function dateGetter(name, size, offset, trim) {
18820   offset = offset || 0;
18821   return function(date) {
18822     var value = date['get' + name]();
18823     if (offset > 0 || value > -offset) {
18824       value += offset;
18825     }
18826     if (value === 0 && offset == -12) value = 12;
18827     return padNumber(value, size, trim);
18828   };
18829 }
18830
18831 function dateStrGetter(name, shortForm) {
18832   return function(date, formats) {
18833     var value = date['get' + name]();
18834     var get = uppercase(shortForm ? ('SHORT' + name) : name);
18835
18836     return formats[get][value];
18837   };
18838 }
18839
18840 function timeZoneGetter(date, formats, offset) {
18841   var zone = -1 * offset;
18842   var paddedZone = (zone >= 0) ? "+" : "";
18843
18844   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
18845                 padNumber(Math.abs(zone % 60), 2);
18846
18847   return paddedZone;
18848 }
18849
18850 function getFirstThursdayOfYear(year) {
18851     // 0 = index of January
18852     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
18853     // 4 = index of Thursday (+1 to account for 1st = 5)
18854     // 11 = index of *next* Thursday (+1 account for 1st = 12)
18855     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
18856 }
18857
18858 function getThursdayThisWeek(datetime) {
18859     return new Date(datetime.getFullYear(), datetime.getMonth(),
18860       // 4 = index of Thursday
18861       datetime.getDate() + (4 - datetime.getDay()));
18862 }
18863
18864 function weekGetter(size) {
18865    return function(date) {
18866       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
18867          thisThurs = getThursdayThisWeek(date);
18868
18869       var diff = +thisThurs - +firstThurs,
18870          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
18871
18872       return padNumber(result, size);
18873    };
18874 }
18875
18876 function ampmGetter(date, formats) {
18877   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
18878 }
18879
18880 function eraGetter(date, formats) {
18881   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
18882 }
18883
18884 function longEraGetter(date, formats) {
18885   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
18886 }
18887
18888 var DATE_FORMATS = {
18889   yyyy: dateGetter('FullYear', 4),
18890     yy: dateGetter('FullYear', 2, 0, true),
18891      y: dateGetter('FullYear', 1),
18892   MMMM: dateStrGetter('Month'),
18893    MMM: dateStrGetter('Month', true),
18894     MM: dateGetter('Month', 2, 1),
18895      M: dateGetter('Month', 1, 1),
18896     dd: dateGetter('Date', 2),
18897      d: dateGetter('Date', 1),
18898     HH: dateGetter('Hours', 2),
18899      H: dateGetter('Hours', 1),
18900     hh: dateGetter('Hours', 2, -12),
18901      h: dateGetter('Hours', 1, -12),
18902     mm: dateGetter('Minutes', 2),
18903      m: dateGetter('Minutes', 1),
18904     ss: dateGetter('Seconds', 2),
18905      s: dateGetter('Seconds', 1),
18906      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
18907      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
18908    sss: dateGetter('Milliseconds', 3),
18909   EEEE: dateStrGetter('Day'),
18910    EEE: dateStrGetter('Day', true),
18911      a: ampmGetter,
18912      Z: timeZoneGetter,
18913     ww: weekGetter(2),
18914      w: weekGetter(1),
18915      G: eraGetter,
18916      GG: eraGetter,
18917      GGG: eraGetter,
18918      GGGG: longEraGetter
18919 };
18920
18921 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
18922     NUMBER_STRING = /^\-?\d+$/;
18923
18924 /**
18925  * @ngdoc filter
18926  * @name date
18927  * @kind function
18928  *
18929  * @description
18930  *   Formats `date` to a string based on the requested `format`.
18931  *
18932  *   `format` string can be composed of the following elements:
18933  *
18934  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
18935  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
18936  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
18937  *   * `'MMMM'`: Month in year (January-December)
18938  *   * `'MMM'`: Month in year (Jan-Dec)
18939  *   * `'MM'`: Month in year, padded (01-12)
18940  *   * `'M'`: Month in year (1-12)
18941  *   * `'dd'`: Day in month, padded (01-31)
18942  *   * `'d'`: Day in month (1-31)
18943  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
18944  *   * `'EEE'`: Day in Week, (Sun-Sat)
18945  *   * `'HH'`: Hour in day, padded (00-23)
18946  *   * `'H'`: Hour in day (0-23)
18947  *   * `'hh'`: Hour in AM/PM, padded (01-12)
18948  *   * `'h'`: Hour in AM/PM, (1-12)
18949  *   * `'mm'`: Minute in hour, padded (00-59)
18950  *   * `'m'`: Minute in hour (0-59)
18951  *   * `'ss'`: Second in minute, padded (00-59)
18952  *   * `'s'`: Second in minute (0-59)
18953  *   * `'sss'`: Millisecond in second, padded (000-999)
18954  *   * `'a'`: AM/PM marker
18955  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
18956  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
18957  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
18958  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
18959  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
18960  *
18961  *   `format` string can also be one of the following predefined
18962  *   {@link guide/i18n localizable formats}:
18963  *
18964  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
18965  *     (e.g. Sep 3, 2010 12:05:08 PM)
18966  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
18967  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
18968  *     (e.g. Friday, September 3, 2010)
18969  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
18970  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
18971  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
18972  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
18973  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
18974  *
18975  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
18976  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
18977  *   (e.g. `"h 'o''clock'"`).
18978  *
18979  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
18980  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
18981  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
18982  *    specified in the string input, the time is considered to be in the local timezone.
18983  * @param {string=} format Formatting rules (see Description). If not specified,
18984  *    `mediumDate` is used.
18985  * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
18986  *    continental US time zone abbreviations, but for general use, use a time zone offset, for
18987  *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
18988  *    If not specified, the timezone of the browser will be used.
18989  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
18990  *
18991  * @example
18992    <example>
18993      <file name="index.html">
18994        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
18995            <span>{{1288323623006 | date:'medium'}}</span><br>
18996        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
18997           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
18998        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
18999           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
19000        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
19001           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
19002      </file>
19003      <file name="protractor.js" type="protractor">
19004        it('should format date', function() {
19005          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
19006             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
19007          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
19008             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
19009          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
19010             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
19011          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
19012             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
19013        });
19014      </file>
19015    </example>
19016  */
19017 dateFilter.$inject = ['$locale'];
19018 function dateFilter($locale) {
19019
19020
19021   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
19022                      // 1        2       3         4          5          6          7          8  9     10      11
19023   function jsonStringToDate(string) {
19024     var match;
19025     if (match = string.match(R_ISO8601_STR)) {
19026       var date = new Date(0),
19027           tzHour = 0,
19028           tzMin  = 0,
19029           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
19030           timeSetter = match[8] ? date.setUTCHours : date.setHours;
19031
19032       if (match[9]) {
19033         tzHour = toInt(match[9] + match[10]);
19034         tzMin = toInt(match[9] + match[11]);
19035       }
19036       dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
19037       var h = toInt(match[4] || 0) - tzHour;
19038       var m = toInt(match[5] || 0) - tzMin;
19039       var s = toInt(match[6] || 0);
19040       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
19041       timeSetter.call(date, h, m, s, ms);
19042       return date;
19043     }
19044     return string;
19045   }
19046
19047
19048   return function(date, format, timezone) {
19049     var text = '',
19050         parts = [],
19051         fn, match;
19052
19053     format = format || 'mediumDate';
19054     format = $locale.DATETIME_FORMATS[format] || format;
19055     if (isString(date)) {
19056       date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
19057     }
19058
19059     if (isNumber(date)) {
19060       date = new Date(date);
19061     }
19062
19063     if (!isDate(date) || !isFinite(date.getTime())) {
19064       return date;
19065     }
19066
19067     while (format) {
19068       match = DATE_FORMATS_SPLIT.exec(format);
19069       if (match) {
19070         parts = concat(parts, match, 1);
19071         format = parts.pop();
19072       } else {
19073         parts.push(format);
19074         format = null;
19075       }
19076     }
19077
19078     var dateTimezoneOffset = date.getTimezoneOffset();
19079     if (timezone) {
19080       dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
19081       date = convertTimezoneToLocal(date, timezone, true);
19082     }
19083     forEach(parts, function(value) {
19084       fn = DATE_FORMATS[value];
19085       text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
19086                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
19087     });
19088
19089     return text;
19090   };
19091 }
19092
19093
19094 /**
19095  * @ngdoc filter
19096  * @name json
19097  * @kind function
19098  *
19099  * @description
19100  *   Allows you to convert a JavaScript object into JSON string.
19101  *
19102  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
19103  *   the binding is automatically converted to JSON.
19104  *
19105  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
19106  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
19107  * @returns {string} JSON string.
19108  *
19109  *
19110  * @example
19111    <example>
19112      <file name="index.html">
19113        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
19114        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
19115      </file>
19116      <file name="protractor.js" type="protractor">
19117        it('should jsonify filtered objects', function() {
19118          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
19119          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
19120        });
19121      </file>
19122    </example>
19123  *
19124  */
19125 function jsonFilter() {
19126   return function(object, spacing) {
19127     if (isUndefined(spacing)) {
19128         spacing = 2;
19129     }
19130     return toJson(object, spacing);
19131   };
19132 }
19133
19134
19135 /**
19136  * @ngdoc filter
19137  * @name lowercase
19138  * @kind function
19139  * @description
19140  * Converts string to lowercase.
19141  * @see angular.lowercase
19142  */
19143 var lowercaseFilter = valueFn(lowercase);
19144
19145
19146 /**
19147  * @ngdoc filter
19148  * @name uppercase
19149  * @kind function
19150  * @description
19151  * Converts string to uppercase.
19152  * @see angular.uppercase
19153  */
19154 var uppercaseFilter = valueFn(uppercase);
19155
19156 /**
19157  * @ngdoc filter
19158  * @name limitTo
19159  * @kind function
19160  *
19161  * @description
19162  * Creates a new array or string containing only a specified number of elements. The elements
19163  * are taken from either the beginning or the end of the source array, string or number, as specified by
19164  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
19165  * converted to a string.
19166  *
19167  * @param {Array|string|number} input Source array, string or number to be limited.
19168  * @param {string|number} limit The length of the returned array or string. If the `limit` number
19169  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
19170  *     If the number is negative, `limit` number  of items from the end of the source array/string
19171  *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
19172  *     the input will be returned unchanged.
19173  * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
19174  *     indicates an offset from the end of `input`. Defaults to `0`.
19175  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
19176  *     had less than `limit` elements.
19177  *
19178  * @example
19179    <example module="limitToExample">
19180      <file name="index.html">
19181        <script>
19182          angular.module('limitToExample', [])
19183            .controller('ExampleController', ['$scope', function($scope) {
19184              $scope.numbers = [1,2,3,4,5,6,7,8,9];
19185              $scope.letters = "abcdefghi";
19186              $scope.longNumber = 2345432342;
19187              $scope.numLimit = 3;
19188              $scope.letterLimit = 3;
19189              $scope.longNumberLimit = 3;
19190            }]);
19191        </script>
19192        <div ng-controller="ExampleController">
19193          <label>
19194             Limit {{numbers}} to:
19195             <input type="number" step="1" ng-model="numLimit">
19196          </label>
19197          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
19198          <label>
19199             Limit {{letters}} to:
19200             <input type="number" step="1" ng-model="letterLimit">
19201          </label>
19202          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
19203          <label>
19204             Limit {{longNumber}} to:
19205             <input type="number" step="1" ng-model="longNumberLimit">
19206          </label>
19207          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
19208        </div>
19209      </file>
19210      <file name="protractor.js" type="protractor">
19211        var numLimitInput = element(by.model('numLimit'));
19212        var letterLimitInput = element(by.model('letterLimit'));
19213        var longNumberLimitInput = element(by.model('longNumberLimit'));
19214        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
19215        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
19216        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
19217
19218        it('should limit the number array to first three items', function() {
19219          expect(numLimitInput.getAttribute('value')).toBe('3');
19220          expect(letterLimitInput.getAttribute('value')).toBe('3');
19221          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
19222          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
19223          expect(limitedLetters.getText()).toEqual('Output letters: abc');
19224          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
19225        });
19226
19227        // There is a bug in safari and protractor that doesn't like the minus key
19228        // it('should update the output when -3 is entered', function() {
19229        //   numLimitInput.clear();
19230        //   numLimitInput.sendKeys('-3');
19231        //   letterLimitInput.clear();
19232        //   letterLimitInput.sendKeys('-3');
19233        //   longNumberLimitInput.clear();
19234        //   longNumberLimitInput.sendKeys('-3');
19235        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
19236        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
19237        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
19238        // });
19239
19240        it('should not exceed the maximum size of input array', function() {
19241          numLimitInput.clear();
19242          numLimitInput.sendKeys('100');
19243          letterLimitInput.clear();
19244          letterLimitInput.sendKeys('100');
19245          longNumberLimitInput.clear();
19246          longNumberLimitInput.sendKeys('100');
19247          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
19248          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
19249          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
19250        });
19251      </file>
19252    </example>
19253 */
19254 function limitToFilter() {
19255   return function(input, limit, begin) {
19256     if (Math.abs(Number(limit)) === Infinity) {
19257       limit = Number(limit);
19258     } else {
19259       limit = toInt(limit);
19260     }
19261     if (isNaN(limit)) return input;
19262
19263     if (isNumber(input)) input = input.toString();
19264     if (!isArray(input) && !isString(input)) return input;
19265
19266     begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
19267     begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
19268
19269     if (limit >= 0) {
19270       return input.slice(begin, begin + limit);
19271     } else {
19272       if (begin === 0) {
19273         return input.slice(limit, input.length);
19274       } else {
19275         return input.slice(Math.max(0, begin + limit), begin);
19276       }
19277     }
19278   };
19279 }
19280
19281 /**
19282  * @ngdoc filter
19283  * @name orderBy
19284  * @kind function
19285  *
19286  * @description
19287  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
19288  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
19289  * as expected, make sure they are actually being saved as numbers and not strings.
19290  *
19291  * @param {Array} array The array to sort.
19292  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
19293  *    used by the comparator to determine the order of elements.
19294  *
19295  *    Can be one of:
19296  *
19297  *    - `function`: Getter function. The result of this function will be sorted using the
19298  *      `<`, `===`, `>` operator.
19299  *    - `string`: An Angular expression. The result of this expression is used to compare elements
19300  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
19301  *      3 first characters of a property called `name`). The result of a constant expression
19302  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
19303  *      to sort object by the value of their `special name` property). An expression can be
19304  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
19305  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
19306  *      element itself is used to compare where sorting.
19307  *    - `Array`: An array of function or string predicates. The first predicate in the array
19308  *      is used for sorting, but when two items are equivalent, the next predicate is used.
19309  *
19310  *    If the predicate is missing or empty then it defaults to `'+'`.
19311  *
19312  * @param {boolean=} reverse Reverse the order of the array.
19313  * @returns {Array} Sorted copy of the source array.
19314  *
19315  *
19316  * @example
19317  * The example below demonstrates a simple ngRepeat, where the data is sorted
19318  * by age in descending order (predicate is set to `'-age'`).
19319  * `reverse` is not set, which means it defaults to `false`.
19320    <example module="orderByExample">
19321      <file name="index.html">
19322        <script>
19323          angular.module('orderByExample', [])
19324            .controller('ExampleController', ['$scope', function($scope) {
19325              $scope.friends =
19326                  [{name:'John', phone:'555-1212', age:10},
19327                   {name:'Mary', phone:'555-9876', age:19},
19328                   {name:'Mike', phone:'555-4321', age:21},
19329                   {name:'Adam', phone:'555-5678', age:35},
19330                   {name:'Julie', phone:'555-8765', age:29}];
19331            }]);
19332        </script>
19333        <div ng-controller="ExampleController">
19334          <table class="friend">
19335            <tr>
19336              <th>Name</th>
19337              <th>Phone Number</th>
19338              <th>Age</th>
19339            </tr>
19340            <tr ng-repeat="friend in friends | orderBy:'-age'">
19341              <td>{{friend.name}}</td>
19342              <td>{{friend.phone}}</td>
19343              <td>{{friend.age}}</td>
19344            </tr>
19345          </table>
19346        </div>
19347      </file>
19348    </example>
19349  *
19350  * The predicate and reverse parameters can be controlled dynamically through scope properties,
19351  * as shown in the next example.
19352  * @example
19353    <example module="orderByExample">
19354      <file name="index.html">
19355        <script>
19356          angular.module('orderByExample', [])
19357            .controller('ExampleController', ['$scope', function($scope) {
19358              $scope.friends =
19359                  [{name:'John', phone:'555-1212', age:10},
19360                   {name:'Mary', phone:'555-9876', age:19},
19361                   {name:'Mike', phone:'555-4321', age:21},
19362                   {name:'Adam', phone:'555-5678', age:35},
19363                   {name:'Julie', phone:'555-8765', age:29}];
19364              $scope.predicate = 'age';
19365              $scope.reverse = true;
19366              $scope.order = function(predicate) {
19367                $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
19368                $scope.predicate = predicate;
19369              };
19370            }]);
19371        </script>
19372        <style type="text/css">
19373          .sortorder:after {
19374            content: '\25b2';
19375          }
19376          .sortorder.reverse:after {
19377            content: '\25bc';
19378          }
19379        </style>
19380        <div ng-controller="ExampleController">
19381          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19382          <hr/>
19383          [ <a href="" ng-click="predicate=''">unsorted</a> ]
19384          <table class="friend">
19385            <tr>
19386              <th>
19387                <a href="" ng-click="order('name')">Name</a>
19388                <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
19389              </th>
19390              <th>
19391                <a href="" ng-click="order('phone')">Phone Number</a>
19392                <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
19393              </th>
19394              <th>
19395                <a href="" ng-click="order('age')">Age</a>
19396                <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
19397              </th>
19398            </tr>
19399            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19400              <td>{{friend.name}}</td>
19401              <td>{{friend.phone}}</td>
19402              <td>{{friend.age}}</td>
19403            </tr>
19404          </table>
19405        </div>
19406      </file>
19407    </example>
19408  *
19409  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
19410  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
19411  * desired parameters.
19412  *
19413  * Example:
19414  *
19415  * @example
19416   <example module="orderByExample">
19417     <file name="index.html">
19418       <div ng-controller="ExampleController">
19419         <table class="friend">
19420           <tr>
19421             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19422               (<a href="" ng-click="order('-name',false)">^</a>)</th>
19423             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19424             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19425           </tr>
19426           <tr ng-repeat="friend in friends">
19427             <td>{{friend.name}}</td>
19428             <td>{{friend.phone}}</td>
19429             <td>{{friend.age}}</td>
19430           </tr>
19431         </table>
19432       </div>
19433     </file>
19434
19435     <file name="script.js">
19436       angular.module('orderByExample', [])
19437         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
19438           var orderBy = $filter('orderBy');
19439           $scope.friends = [
19440             { name: 'John',    phone: '555-1212',    age: 10 },
19441             { name: 'Mary',    phone: '555-9876',    age: 19 },
19442             { name: 'Mike',    phone: '555-4321',    age: 21 },
19443             { name: 'Adam',    phone: '555-5678',    age: 35 },
19444             { name: 'Julie',   phone: '555-8765',    age: 29 }
19445           ];
19446           $scope.order = function(predicate, reverse) {
19447             $scope.friends = orderBy($scope.friends, predicate, reverse);
19448           };
19449           $scope.order('-age',false);
19450         }]);
19451     </file>
19452 </example>
19453  */
19454 orderByFilter.$inject = ['$parse'];
19455 function orderByFilter($parse) {
19456   return function(array, sortPredicate, reverseOrder) {
19457
19458     if (!(isArrayLike(array))) return array;
19459
19460     if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
19461     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
19462
19463     var predicates = processPredicates(sortPredicate, reverseOrder);
19464     // Add a predicate at the end that evaluates to the element index. This makes the
19465     // sort stable as it works as a tie-breaker when all the input predicates cannot
19466     // distinguish between two elements.
19467     predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
19468
19469     // The next three lines are a version of a Swartzian Transform idiom from Perl
19470     // (sometimes called the Decorate-Sort-Undecorate idiom)
19471     // See https://en.wikipedia.org/wiki/Schwartzian_transform
19472     var compareValues = Array.prototype.map.call(array, getComparisonObject);
19473     compareValues.sort(doComparison);
19474     array = compareValues.map(function(item) { return item.value; });
19475
19476     return array;
19477
19478     function getComparisonObject(value, index) {
19479       return {
19480         value: value,
19481         predicateValues: predicates.map(function(predicate) {
19482           return getPredicateValue(predicate.get(value), index);
19483         })
19484       };
19485     }
19486
19487     function doComparison(v1, v2) {
19488       var result = 0;
19489       for (var index=0, length = predicates.length; index < length; ++index) {
19490         result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
19491         if (result) break;
19492       }
19493       return result;
19494     }
19495   };
19496
19497   function processPredicates(sortPredicate, reverseOrder) {
19498     reverseOrder = reverseOrder ? -1 : 1;
19499     return sortPredicate.map(function(predicate) {
19500       var descending = 1, get = identity;
19501
19502       if (isFunction(predicate)) {
19503         get = predicate;
19504       } else if (isString(predicate)) {
19505         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
19506           descending = predicate.charAt(0) == '-' ? -1 : 1;
19507           predicate = predicate.substring(1);
19508         }
19509         if (predicate !== '') {
19510           get = $parse(predicate);
19511           if (get.constant) {
19512             var key = get();
19513             get = function(value) { return value[key]; };
19514           }
19515         }
19516       }
19517       return { get: get, descending: descending * reverseOrder };
19518     });
19519   }
19520
19521   function isPrimitive(value) {
19522     switch (typeof value) {
19523       case 'number': /* falls through */
19524       case 'boolean': /* falls through */
19525       case 'string':
19526         return true;
19527       default:
19528         return false;
19529     }
19530   }
19531
19532   function objectValue(value, index) {
19533     // If `valueOf` is a valid function use that
19534     if (typeof value.valueOf === 'function') {
19535       value = value.valueOf();
19536       if (isPrimitive(value)) return value;
19537     }
19538     // If `toString` is a valid function and not the one from `Object.prototype` use that
19539     if (hasCustomToString(value)) {
19540       value = value.toString();
19541       if (isPrimitive(value)) return value;
19542     }
19543     // We have a basic object so we use the position of the object in the collection
19544     return index;
19545   }
19546
19547   function getPredicateValue(value, index) {
19548     var type = typeof value;
19549     if (value === null) {
19550       type = 'string';
19551       value = 'null';
19552     } else if (type === 'string') {
19553       value = value.toLowerCase();
19554     } else if (type === 'object') {
19555       value = objectValue(value, index);
19556     }
19557     return { value: value, type: type };
19558   }
19559
19560   function compare(v1, v2) {
19561     var result = 0;
19562     if (v1.type === v2.type) {
19563       if (v1.value !== v2.value) {
19564         result = v1.value < v2.value ? -1 : 1;
19565       }
19566     } else {
19567       result = v1.type < v2.type ? -1 : 1;
19568     }
19569     return result;
19570   }
19571 }
19572
19573 function ngDirective(directive) {
19574   if (isFunction(directive)) {
19575     directive = {
19576       link: directive
19577     };
19578   }
19579   directive.restrict = directive.restrict || 'AC';
19580   return valueFn(directive);
19581 }
19582
19583 /**
19584  * @ngdoc directive
19585  * @name a
19586  * @restrict E
19587  *
19588  * @description
19589  * Modifies the default behavior of the html A tag so that the default action is prevented when
19590  * the href attribute is empty.
19591  *
19592  * This change permits the easy creation of action links with the `ngClick` directive
19593  * without changing the location or causing page reloads, e.g.:
19594  * `<a href="" ng-click="list.addItem()">Add Item</a>`
19595  */
19596 var htmlAnchorDirective = valueFn({
19597   restrict: 'E',
19598   compile: function(element, attr) {
19599     if (!attr.href && !attr.xlinkHref) {
19600       return function(scope, element) {
19601         // If the linked element is not an anchor tag anymore, do nothing
19602         if (element[0].nodeName.toLowerCase() !== 'a') return;
19603
19604         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
19605         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
19606                    'xlink:href' : 'href';
19607         element.on('click', function(event) {
19608           // if we have no href url, then don't navigate anywhere.
19609           if (!element.attr(href)) {
19610             event.preventDefault();
19611           }
19612         });
19613       };
19614     }
19615   }
19616 });
19617
19618 /**
19619  * @ngdoc directive
19620  * @name ngHref
19621  * @restrict A
19622  * @priority 99
19623  *
19624  * @description
19625  * Using Angular markup like `{{hash}}` in an href attribute will
19626  * make the link go to the wrong URL if the user clicks it before
19627  * Angular has a chance to replace the `{{hash}}` markup with its
19628  * value. Until Angular replaces the markup the link will be broken
19629  * and will most likely return a 404 error. The `ngHref` directive
19630  * solves this problem.
19631  *
19632  * The wrong way to write it:
19633  * ```html
19634  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19635  * ```
19636  *
19637  * The correct way to write it:
19638  * ```html
19639  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19640  * ```
19641  *
19642  * @element A
19643  * @param {template} ngHref any string which can contain `{{}}` markup.
19644  *
19645  * @example
19646  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
19647  * in links and their different behaviors:
19648     <example>
19649       <file name="index.html">
19650         <input ng-model="value" /><br />
19651         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
19652         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
19653         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
19654         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
19655         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
19656         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
19657       </file>
19658       <file name="protractor.js" type="protractor">
19659         it('should execute ng-click but not reload when href without value', function() {
19660           element(by.id('link-1')).click();
19661           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
19662           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
19663         });
19664
19665         it('should execute ng-click but not reload when href empty string', function() {
19666           element(by.id('link-2')).click();
19667           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
19668           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
19669         });
19670
19671         it('should execute ng-click and change url when ng-href specified', function() {
19672           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
19673
19674           element(by.id('link-3')).click();
19675
19676           // At this point, we navigate away from an Angular page, so we need
19677           // to use browser.driver to get the base webdriver.
19678
19679           browser.wait(function() {
19680             return browser.driver.getCurrentUrl().then(function(url) {
19681               return url.match(/\/123$/);
19682             });
19683           }, 5000, 'page should navigate to /123');
19684         });
19685
19686         it('should execute ng-click but not reload when href empty string and name specified', function() {
19687           element(by.id('link-4')).click();
19688           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
19689           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
19690         });
19691
19692         it('should execute ng-click but not reload when no href but name specified', function() {
19693           element(by.id('link-5')).click();
19694           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
19695           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
19696         });
19697
19698         it('should only change url when only ng-href', function() {
19699           element(by.model('value')).clear();
19700           element(by.model('value')).sendKeys('6');
19701           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
19702
19703           element(by.id('link-6')).click();
19704
19705           // At this point, we navigate away from an Angular page, so we need
19706           // to use browser.driver to get the base webdriver.
19707           browser.wait(function() {
19708             return browser.driver.getCurrentUrl().then(function(url) {
19709               return url.match(/\/6$/);
19710             });
19711           }, 5000, 'page should navigate to /6');
19712         });
19713       </file>
19714     </example>
19715  */
19716
19717 /**
19718  * @ngdoc directive
19719  * @name ngSrc
19720  * @restrict A
19721  * @priority 99
19722  *
19723  * @description
19724  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
19725  * work right: The browser will fetch from the URL with the literal
19726  * text `{{hash}}` until Angular replaces the expression inside
19727  * `{{hash}}`. The `ngSrc` directive solves this problem.
19728  *
19729  * The buggy way to write it:
19730  * ```html
19731  * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
19732  * ```
19733  *
19734  * The correct way to write it:
19735  * ```html
19736  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
19737  * ```
19738  *
19739  * @element IMG
19740  * @param {template} ngSrc any string which can contain `{{}}` markup.
19741  */
19742
19743 /**
19744  * @ngdoc directive
19745  * @name ngSrcset
19746  * @restrict A
19747  * @priority 99
19748  *
19749  * @description
19750  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
19751  * work right: The browser will fetch from the URL with the literal
19752  * text `{{hash}}` until Angular replaces the expression inside
19753  * `{{hash}}`. The `ngSrcset` directive solves this problem.
19754  *
19755  * The buggy way to write it:
19756  * ```html
19757  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
19758  * ```
19759  *
19760  * The correct way to write it:
19761  * ```html
19762  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
19763  * ```
19764  *
19765  * @element IMG
19766  * @param {template} ngSrcset any string which can contain `{{}}` markup.
19767  */
19768
19769 /**
19770  * @ngdoc directive
19771  * @name ngDisabled
19772  * @restrict A
19773  * @priority 100
19774  *
19775  * @description
19776  *
19777  * This directive sets the `disabled` attribute on the element if the
19778  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19779  *
19780  * A special directive is necessary because we cannot use interpolation inside the `disabled`
19781  * attribute.  The following example would make the button enabled on Chrome/Firefox
19782  * but not on older IEs:
19783  *
19784  * ```html
19785  * <!-- See below for an example of ng-disabled being used correctly -->
19786  * <div ng-init="isDisabled = false">
19787  *  <button disabled="{{isDisabled}}">Disabled</button>
19788  * </div>
19789  * ```
19790  *
19791  * This is because the HTML specification does not require browsers to preserve the values of
19792  * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19793  * If we put an Angular interpolation expression into such an attribute then the
19794  * binding information would be lost when the browser removes the attribute.
19795  *
19796  * @example
19797     <example>
19798       <file name="index.html">
19799         <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
19800         <button ng-model="button" ng-disabled="checked">Button</button>
19801       </file>
19802       <file name="protractor.js" type="protractor">
19803         it('should toggle button', function() {
19804           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
19805           element(by.model('checked')).click();
19806           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
19807         });
19808       </file>
19809     </example>
19810  *
19811  * @element INPUT
19812  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
19813  *     then the `disabled` attribute will be set on the element
19814  */
19815
19816
19817 /**
19818  * @ngdoc directive
19819  * @name ngChecked
19820  * @restrict A
19821  * @priority 100
19822  *
19823  * @description
19824  * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
19825  *
19826  * Note that this directive should not be used together with {@link ngModel `ngModel`},
19827  * as this can lead to unexpected behavior.
19828  *
19829  * ### Why do we need `ngChecked`?
19830  *
19831  * The HTML specification does not require browsers to preserve the values of boolean attributes
19832  * such as checked. (Their presence means true and their absence means false.)
19833  * If we put an Angular interpolation expression into such an attribute then the
19834  * binding information would be lost when the browser removes the attribute.
19835  * The `ngChecked` directive solves this problem for the `checked` attribute.
19836  * This complementary directive is not removed by the browser and so provides
19837  * a permanent reliable place to store the binding information.
19838  * @example
19839     <example>
19840       <file name="index.html">
19841         <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
19842         <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
19843       </file>
19844       <file name="protractor.js" type="protractor">
19845         it('should check both checkBoxes', function() {
19846           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
19847           element(by.model('master')).click();
19848           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
19849         });
19850       </file>
19851     </example>
19852  *
19853  * @element INPUT
19854  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
19855  *     then the `checked` attribute will be set on the element
19856  */
19857
19858
19859 /**
19860  * @ngdoc directive
19861  * @name ngReadonly
19862  * @restrict A
19863  * @priority 100
19864  *
19865  * @description
19866  * The HTML specification does not require browsers to preserve the values of boolean attributes
19867  * such as readonly. (Their presence means true and their absence means false.)
19868  * If we put an Angular interpolation expression into such an attribute then the
19869  * binding information would be lost when the browser removes the attribute.
19870  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19871  * This complementary directive is not removed by the browser and so provides
19872  * a permanent reliable place to store the binding information.
19873  * @example
19874     <example>
19875       <file name="index.html">
19876         <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
19877         <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
19878       </file>
19879       <file name="protractor.js" type="protractor">
19880         it('should toggle readonly attr', function() {
19881           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
19882           element(by.model('checked')).click();
19883           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
19884         });
19885       </file>
19886     </example>
19887  *
19888  * @element INPUT
19889  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
19890  *     then special attribute "readonly" will be set on the element
19891  */
19892
19893
19894 /**
19895  * @ngdoc directive
19896  * @name ngSelected
19897  * @restrict A
19898  * @priority 100
19899  *
19900  * @description
19901  * The HTML specification does not require browsers to preserve the values of boolean attributes
19902  * such as selected. (Their presence means true and their absence means false.)
19903  * If we put an Angular interpolation expression into such an attribute then the
19904  * binding information would be lost when the browser removes the attribute.
19905  * The `ngSelected` directive solves this problem for the `selected` attribute.
19906  * This complementary directive is not removed by the browser and so provides
19907  * a permanent reliable place to store the binding information.
19908  *
19909  * @example
19910     <example>
19911       <file name="index.html">
19912         <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
19913         <select aria-label="ngSelected demo">
19914           <option>Hello!</option>
19915           <option id="greet" ng-selected="selected">Greetings!</option>
19916         </select>
19917       </file>
19918       <file name="protractor.js" type="protractor">
19919         it('should select Greetings!', function() {
19920           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
19921           element(by.model('selected')).click();
19922           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
19923         });
19924       </file>
19925     </example>
19926  *
19927  * @element OPTION
19928  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
19929  *     then special attribute "selected" will be set on the element
19930  */
19931
19932 /**
19933  * @ngdoc directive
19934  * @name ngOpen
19935  * @restrict A
19936  * @priority 100
19937  *
19938  * @description
19939  * The HTML specification does not require browsers to preserve the values of boolean attributes
19940  * such as open. (Their presence means true and their absence means false.)
19941  * If we put an Angular interpolation expression into such an attribute then the
19942  * binding information would be lost when the browser removes the attribute.
19943  * The `ngOpen` directive solves this problem for the `open` attribute.
19944  * This complementary directive is not removed by the browser and so provides
19945  * a permanent reliable place to store the binding information.
19946  * @example
19947      <example>
19948        <file name="index.html">
19949          <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
19950          <details id="details" ng-open="open">
19951             <summary>Show/Hide me</summary>
19952          </details>
19953        </file>
19954        <file name="protractor.js" type="protractor">
19955          it('should toggle open', function() {
19956            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
19957            element(by.model('open')).click();
19958            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
19959          });
19960        </file>
19961      </example>
19962  *
19963  * @element DETAILS
19964  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
19965  *     then special attribute "open" will be set on the element
19966  */
19967
19968 var ngAttributeAliasDirectives = {};
19969
19970 // boolean attrs are evaluated
19971 forEach(BOOLEAN_ATTR, function(propName, attrName) {
19972   // binding to multiple is not supported
19973   if (propName == "multiple") return;
19974
19975   function defaultLinkFn(scope, element, attr) {
19976     scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
19977       attr.$set(attrName, !!value);
19978     });
19979   }
19980
19981   var normalized = directiveNormalize('ng-' + attrName);
19982   var linkFn = defaultLinkFn;
19983
19984   if (propName === 'checked') {
19985     linkFn = function(scope, element, attr) {
19986       // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
19987       if (attr.ngModel !== attr[normalized]) {
19988         defaultLinkFn(scope, element, attr);
19989       }
19990     };
19991   }
19992
19993   ngAttributeAliasDirectives[normalized] = function() {
19994     return {
19995       restrict: 'A',
19996       priority: 100,
19997       link: linkFn
19998     };
19999   };
20000 });
20001
20002 // aliased input attrs are evaluated
20003 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
20004   ngAttributeAliasDirectives[ngAttr] = function() {
20005     return {
20006       priority: 100,
20007       link: function(scope, element, attr) {
20008         //special case ngPattern when a literal regular expression value
20009         //is used as the expression (this way we don't have to watch anything).
20010         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
20011           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
20012           if (match) {
20013             attr.$set("ngPattern", new RegExp(match[1], match[2]));
20014             return;
20015           }
20016         }
20017
20018         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
20019           attr.$set(ngAttr, value);
20020         });
20021       }
20022     };
20023   };
20024 });
20025
20026 // ng-src, ng-srcset, ng-href are interpolated
20027 forEach(['src', 'srcset', 'href'], function(attrName) {
20028   var normalized = directiveNormalize('ng-' + attrName);
20029   ngAttributeAliasDirectives[normalized] = function() {
20030     return {
20031       priority: 99, // it needs to run after the attributes are interpolated
20032       link: function(scope, element, attr) {
20033         var propName = attrName,
20034             name = attrName;
20035
20036         if (attrName === 'href' &&
20037             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
20038           name = 'xlinkHref';
20039           attr.$attr[name] = 'xlink:href';
20040           propName = null;
20041         }
20042
20043         attr.$observe(normalized, function(value) {
20044           if (!value) {
20045             if (attrName === 'href') {
20046               attr.$set(name, null);
20047             }
20048             return;
20049           }
20050
20051           attr.$set(name, value);
20052
20053           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
20054           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
20055           // to set the property as well to achieve the desired effect.
20056           // we use attr[attrName] value since $set can sanitize the url.
20057           if (msie && propName) element.prop(propName, attr[name]);
20058         });
20059       }
20060     };
20061   };
20062 });
20063
20064 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
20065  */
20066 var nullFormCtrl = {
20067   $addControl: noop,
20068   $$renameControl: nullFormRenameControl,
20069   $removeControl: noop,
20070   $setValidity: noop,
20071   $setDirty: noop,
20072   $setPristine: noop,
20073   $setSubmitted: noop
20074 },
20075 SUBMITTED_CLASS = 'ng-submitted';
20076
20077 function nullFormRenameControl(control, name) {
20078   control.$name = name;
20079 }
20080
20081 /**
20082  * @ngdoc type
20083  * @name form.FormController
20084  *
20085  * @property {boolean} $pristine True if user has not interacted with the form yet.
20086  * @property {boolean} $dirty True if user has already interacted with the form.
20087  * @property {boolean} $valid True if all of the containing forms and controls are valid.
20088  * @property {boolean} $invalid True if at least one containing control or form is invalid.
20089  * @property {boolean} $pending True if at least one containing control or form is pending.
20090  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
20091  *
20092  * @property {Object} $error Is an object hash, containing references to controls or
20093  *  forms with failing validators, where:
20094  *
20095  *  - keys are validation tokens (error names),
20096  *  - values are arrays of controls or forms that have a failing validator for given error name.
20097  *
20098  *  Built-in validation tokens:
20099  *
20100  *  - `email`
20101  *  - `max`
20102  *  - `maxlength`
20103  *  - `min`
20104  *  - `minlength`
20105  *  - `number`
20106  *  - `pattern`
20107  *  - `required`
20108  *  - `url`
20109  *  - `date`
20110  *  - `datetimelocal`
20111  *  - `time`
20112  *  - `week`
20113  *  - `month`
20114  *
20115  * @description
20116  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
20117  * such as being valid/invalid or dirty/pristine.
20118  *
20119  * Each {@link ng.directive:form form} directive creates an instance
20120  * of `FormController`.
20121  *
20122  */
20123 //asks for $scope to fool the BC controller module
20124 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
20125 function FormController(element, attrs, $scope, $animate, $interpolate) {
20126   var form = this,
20127       controls = [];
20128
20129   // init state
20130   form.$error = {};
20131   form.$$success = {};
20132   form.$pending = undefined;
20133   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
20134   form.$dirty = false;
20135   form.$pristine = true;
20136   form.$valid = true;
20137   form.$invalid = false;
20138   form.$submitted = false;
20139   form.$$parentForm = nullFormCtrl;
20140
20141   /**
20142    * @ngdoc method
20143    * @name form.FormController#$rollbackViewValue
20144    *
20145    * @description
20146    * Rollback all form controls pending updates to the `$modelValue`.
20147    *
20148    * Updates may be pending by a debounced event or because the input is waiting for a some future
20149    * event defined in `ng-model-options`. This method is typically needed by the reset button of
20150    * a form that uses `ng-model-options` to pend updates.
20151    */
20152   form.$rollbackViewValue = function() {
20153     forEach(controls, function(control) {
20154       control.$rollbackViewValue();
20155     });
20156   };
20157
20158   /**
20159    * @ngdoc method
20160    * @name form.FormController#$commitViewValue
20161    *
20162    * @description
20163    * Commit all form controls pending updates to the `$modelValue`.
20164    *
20165    * Updates may be pending by a debounced event or because the input is waiting for a some future
20166    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
20167    * usually handles calling this in response to input events.
20168    */
20169   form.$commitViewValue = function() {
20170     forEach(controls, function(control) {
20171       control.$commitViewValue();
20172     });
20173   };
20174
20175   /**
20176    * @ngdoc method
20177    * @name form.FormController#$addControl
20178    * @param {object} control control object, either a {@link form.FormController} or an
20179    * {@link ngModel.NgModelController}
20180    *
20181    * @description
20182    * Register a control with the form. Input elements using ngModelController do this automatically
20183    * when they are linked.
20184    *
20185    * Note that the current state of the control will not be reflected on the new parent form. This
20186    * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
20187    * state.
20188    *
20189    * However, if the method is used programmatically, for example by adding dynamically created controls,
20190    * or controls that have been previously removed without destroying their corresponding DOM element,
20191    * it's the developers responsiblity to make sure the current state propagates to the parent form.
20192    *
20193    * For example, if an input control is added that is already `$dirty` and has `$error` properties,
20194    * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
20195    */
20196   form.$addControl = function(control) {
20197     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
20198     // and not added to the scope.  Now we throw an error.
20199     assertNotHasOwnProperty(control.$name, 'input');
20200     controls.push(control);
20201
20202     if (control.$name) {
20203       form[control.$name] = control;
20204     }
20205
20206     control.$$parentForm = form;
20207   };
20208
20209   // Private API: rename a form control
20210   form.$$renameControl = function(control, newName) {
20211     var oldName = control.$name;
20212
20213     if (form[oldName] === control) {
20214       delete form[oldName];
20215     }
20216     form[newName] = control;
20217     control.$name = newName;
20218   };
20219
20220   /**
20221    * @ngdoc method
20222    * @name form.FormController#$removeControl
20223    * @param {object} control control object, either a {@link form.FormController} or an
20224    * {@link ngModel.NgModelController}
20225    *
20226    * @description
20227    * Deregister a control from the form.
20228    *
20229    * Input elements using ngModelController do this automatically when they are destroyed.
20230    *
20231    * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
20232    * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
20233    * different from case to case. For example, removing the only `$dirty` control from a form may or
20234    * may not mean that the form is still `$dirty`.
20235    */
20236   form.$removeControl = function(control) {
20237     if (control.$name && form[control.$name] === control) {
20238       delete form[control.$name];
20239     }
20240     forEach(form.$pending, function(value, name) {
20241       form.$setValidity(name, null, control);
20242     });
20243     forEach(form.$error, function(value, name) {
20244       form.$setValidity(name, null, control);
20245     });
20246     forEach(form.$$success, function(value, name) {
20247       form.$setValidity(name, null, control);
20248     });
20249
20250     arrayRemove(controls, control);
20251     control.$$parentForm = nullFormCtrl;
20252   };
20253
20254
20255   /**
20256    * @ngdoc method
20257    * @name form.FormController#$setValidity
20258    *
20259    * @description
20260    * Sets the validity of a form control.
20261    *
20262    * This method will also propagate to parent forms.
20263    */
20264   addSetValidityMethod({
20265     ctrl: this,
20266     $element: element,
20267     set: function(object, property, controller) {
20268       var list = object[property];
20269       if (!list) {
20270         object[property] = [controller];
20271       } else {
20272         var index = list.indexOf(controller);
20273         if (index === -1) {
20274           list.push(controller);
20275         }
20276       }
20277     },
20278     unset: function(object, property, controller) {
20279       var list = object[property];
20280       if (!list) {
20281         return;
20282       }
20283       arrayRemove(list, controller);
20284       if (list.length === 0) {
20285         delete object[property];
20286       }
20287     },
20288     $animate: $animate
20289   });
20290
20291   /**
20292    * @ngdoc method
20293    * @name form.FormController#$setDirty
20294    *
20295    * @description
20296    * Sets the form to a dirty state.
20297    *
20298    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
20299    * state (ng-dirty class). This method will also propagate to parent forms.
20300    */
20301   form.$setDirty = function() {
20302     $animate.removeClass(element, PRISTINE_CLASS);
20303     $animate.addClass(element, DIRTY_CLASS);
20304     form.$dirty = true;
20305     form.$pristine = false;
20306     form.$$parentForm.$setDirty();
20307   };
20308
20309   /**
20310    * @ngdoc method
20311    * @name form.FormController#$setPristine
20312    *
20313    * @description
20314    * Sets the form to its pristine state.
20315    *
20316    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
20317    * state (ng-pristine class). This method will also propagate to all the controls contained
20318    * in this form.
20319    *
20320    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
20321    * saving or resetting it.
20322    */
20323   form.$setPristine = function() {
20324     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
20325     form.$dirty = false;
20326     form.$pristine = true;
20327     form.$submitted = false;
20328     forEach(controls, function(control) {
20329       control.$setPristine();
20330     });
20331   };
20332
20333   /**
20334    * @ngdoc method
20335    * @name form.FormController#$setUntouched
20336    *
20337    * @description
20338    * Sets the form to its untouched state.
20339    *
20340    * This method can be called to remove the 'ng-touched' class and set the form controls to their
20341    * untouched state (ng-untouched class).
20342    *
20343    * Setting a form controls back to their untouched state is often useful when setting the form
20344    * back to its pristine state.
20345    */
20346   form.$setUntouched = function() {
20347     forEach(controls, function(control) {
20348       control.$setUntouched();
20349     });
20350   };
20351
20352   /**
20353    * @ngdoc method
20354    * @name form.FormController#$setSubmitted
20355    *
20356    * @description
20357    * Sets the form to its submitted state.
20358    */
20359   form.$setSubmitted = function() {
20360     $animate.addClass(element, SUBMITTED_CLASS);
20361     form.$submitted = true;
20362     form.$$parentForm.$setSubmitted();
20363   };
20364 }
20365
20366 /**
20367  * @ngdoc directive
20368  * @name ngForm
20369  * @restrict EAC
20370  *
20371  * @description
20372  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
20373  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
20374  * sub-group of controls needs to be determined.
20375  *
20376  * Note: the purpose of `ngForm` is to group controls,
20377  * but not to be a replacement for the `<form>` tag with all of its capabilities
20378  * (e.g. posting to the server, ...).
20379  *
20380  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
20381  *                       related scope, under this name.
20382  *
20383  */
20384
20385  /**
20386  * @ngdoc directive
20387  * @name form
20388  * @restrict E
20389  *
20390  * @description
20391  * Directive that instantiates
20392  * {@link form.FormController FormController}.
20393  *
20394  * If the `name` attribute is specified, the form controller is published onto the current scope under
20395  * this name.
20396  *
20397  * # Alias: {@link ng.directive:ngForm `ngForm`}
20398  *
20399  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
20400  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
20401  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
20402  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
20403  * using Angular validation directives in forms that are dynamically generated using the
20404  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
20405  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
20406  * `ngForm` directive and nest these in an outer `form` element.
20407  *
20408  *
20409  * # CSS classes
20410  *  - `ng-valid` is set if the form is valid.
20411  *  - `ng-invalid` is set if the form is invalid.
20412  *  - `ng-pending` is set if the form is pending.
20413  *  - `ng-pristine` is set if the form is pristine.
20414  *  - `ng-dirty` is set if the form is dirty.
20415  *  - `ng-submitted` is set if the form was submitted.
20416  *
20417  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
20418  *
20419  *
20420  * # Submitting a form and preventing the default action
20421  *
20422  * Since the role of forms in client-side Angular applications is different than in classical
20423  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
20424  * page reload that sends the data to the server. Instead some javascript logic should be triggered
20425  * to handle the form submission in an application-specific way.
20426  *
20427  * For this reason, Angular prevents the default action (form submission to the server) unless the
20428  * `<form>` element has an `action` attribute specified.
20429  *
20430  * You can use one of the following two ways to specify what javascript method should be called when
20431  * a form is submitted:
20432  *
20433  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
20434  * - {@link ng.directive:ngClick ngClick} directive on the first
20435   *  button or input field of type submit (input[type=submit])
20436  *
20437  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
20438  * or {@link ng.directive:ngClick ngClick} directives.
20439  * This is because of the following form submission rules in the HTML specification:
20440  *
20441  * - If a form has only one input field then hitting enter in this field triggers form submit
20442  * (`ngSubmit`)
20443  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
20444  * doesn't trigger submit
20445  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
20446  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
20447  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
20448  *
20449  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
20450  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
20451  * to have access to the updated model.
20452  *
20453  * ## Animation Hooks
20454  *
20455  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
20456  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
20457  * other validations that are performed within the form. Animations in ngForm are similar to how
20458  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
20459  * as JS animations.
20460  *
20461  * The following example shows a simple way to utilize CSS transitions to style a form element
20462  * that has been rendered as invalid after it has been validated:
20463  *
20464  * <pre>
20465  * //be sure to include ngAnimate as a module to hook into more
20466  * //advanced animations
20467  * .my-form {
20468  *   transition:0.5s linear all;
20469  *   background: white;
20470  * }
20471  * .my-form.ng-invalid {
20472  *   background: red;
20473  *   color:white;
20474  * }
20475  * </pre>
20476  *
20477  * @example
20478     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
20479       <file name="index.html">
20480        <script>
20481          angular.module('formExample', [])
20482            .controller('FormController', ['$scope', function($scope) {
20483              $scope.userType = 'guest';
20484            }]);
20485        </script>
20486        <style>
20487         .my-form {
20488           transition:all linear 0.5s;
20489           background: transparent;
20490         }
20491         .my-form.ng-invalid {
20492           background: red;
20493         }
20494        </style>
20495        <form name="myForm" ng-controller="FormController" class="my-form">
20496          userType: <input name="input" ng-model="userType" required>
20497          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20498          <code>userType = {{userType}}</code><br>
20499          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
20500          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
20501          <code>myForm.$valid = {{myForm.$valid}}</code><br>
20502          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
20503         </form>
20504       </file>
20505       <file name="protractor.js" type="protractor">
20506         it('should initialize to model', function() {
20507           var userType = element(by.binding('userType'));
20508           var valid = element(by.binding('myForm.input.$valid'));
20509
20510           expect(userType.getText()).toContain('guest');
20511           expect(valid.getText()).toContain('true');
20512         });
20513
20514         it('should be invalid if empty', function() {
20515           var userType = element(by.binding('userType'));
20516           var valid = element(by.binding('myForm.input.$valid'));
20517           var userInput = element(by.model('userType'));
20518
20519           userInput.clear();
20520           userInput.sendKeys('');
20521
20522           expect(userType.getText()).toEqual('userType =');
20523           expect(valid.getText()).toContain('false');
20524         });
20525       </file>
20526     </example>
20527  *
20528  * @param {string=} name Name of the form. If specified, the form controller will be published into
20529  *                       related scope, under this name.
20530  */
20531 var formDirectiveFactory = function(isNgForm) {
20532   return ['$timeout', '$parse', function($timeout, $parse) {
20533     var formDirective = {
20534       name: 'form',
20535       restrict: isNgForm ? 'EAC' : 'E',
20536       require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
20537       controller: FormController,
20538       compile: function ngFormCompile(formElement, attr) {
20539         // Setup initial state of the control
20540         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
20541
20542         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
20543
20544         return {
20545           pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
20546             var controller = ctrls[0];
20547
20548             // if `action` attr is not present on the form, prevent the default action (submission)
20549             if (!('action' in attr)) {
20550               // we can't use jq events because if a form is destroyed during submission the default
20551               // action is not prevented. see #1238
20552               //
20553               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
20554               // page reload if the form was destroyed by submission of the form via a click handler
20555               // on a button in the form. Looks like an IE9 specific bug.
20556               var handleFormSubmission = function(event) {
20557                 scope.$apply(function() {
20558                   controller.$commitViewValue();
20559                   controller.$setSubmitted();
20560                 });
20561
20562                 event.preventDefault();
20563               };
20564
20565               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20566
20567               // unregister the preventDefault listener so that we don't not leak memory but in a
20568               // way that will achieve the prevention of the default action.
20569               formElement.on('$destroy', function() {
20570                 $timeout(function() {
20571                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20572                 }, 0, false);
20573               });
20574             }
20575
20576             var parentFormCtrl = ctrls[1] || controller.$$parentForm;
20577             parentFormCtrl.$addControl(controller);
20578
20579             var setter = nameAttr ? getSetter(controller.$name) : noop;
20580
20581             if (nameAttr) {
20582               setter(scope, controller);
20583               attr.$observe(nameAttr, function(newValue) {
20584                 if (controller.$name === newValue) return;
20585                 setter(scope, undefined);
20586                 controller.$$parentForm.$$renameControl(controller, newValue);
20587                 setter = getSetter(controller.$name);
20588                 setter(scope, controller);
20589               });
20590             }
20591             formElement.on('$destroy', function() {
20592               controller.$$parentForm.$removeControl(controller);
20593               setter(scope, undefined);
20594               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
20595             });
20596           }
20597         };
20598       }
20599     };
20600
20601     return formDirective;
20602
20603     function getSetter(expression) {
20604       if (expression === '') {
20605         //create an assignable expression, so forms with an empty name can be renamed later
20606         return $parse('this[""]').assign;
20607       }
20608       return $parse(expression).assign || noop;
20609     }
20610   }];
20611 };
20612
20613 var formDirective = formDirectiveFactory();
20614 var ngFormDirective = formDirectiveFactory(true);
20615
20616 /* global VALID_CLASS: false,
20617   INVALID_CLASS: false,
20618   PRISTINE_CLASS: false,
20619   DIRTY_CLASS: false,
20620   UNTOUCHED_CLASS: false,
20621   TOUCHED_CLASS: false,
20622   ngModelMinErr: false,
20623 */
20624
20625 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20626 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)/;
20627 // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20628 var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
20629 var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
20630 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20631 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
20632 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20633 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
20634 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
20635 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20636
20637 var inputType = {
20638
20639   /**
20640    * @ngdoc input
20641    * @name input[text]
20642    *
20643    * @description
20644    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
20645    *
20646    *
20647    * @param {string} ngModel Assignable angular expression to data-bind to.
20648    * @param {string=} name Property name of the form under which the control is published.
20649    * @param {string=} required Adds `required` validation error key if the value is not entered.
20650    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20651    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20652    *    `required` when you want to data-bind to the `required` attribute.
20653    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20654    *    minlength.
20655    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20656    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20657    *    any length.
20658    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20659    *    that contains the regular expression body that will be converted to a regular expression
20660    *    as in the ngPattern directive.
20661    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20662    *    a RegExp found by evaluating the Angular expression given in the attribute value.
20663    *    If the expression evaluates to a RegExp object, then this is used directly.
20664    *    If the expression evaluates to a string, then it will be converted to a RegExp
20665    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20666    *    `new RegExp('^abc$')`.<br />
20667    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20668    *    start at the index of the last search's match, thus not taking the whole input value into
20669    *    account.
20670    * @param {string=} ngChange Angular expression to be executed when input changes due to user
20671    *    interaction with the input element.
20672    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20673    *    This parameter is ignored for input[type=password] controls, which will never trim the
20674    *    input.
20675    *
20676    * @example
20677       <example name="text-input-directive" module="textInputExample">
20678         <file name="index.html">
20679          <script>
20680            angular.module('textInputExample', [])
20681              .controller('ExampleController', ['$scope', function($scope) {
20682                $scope.example = {
20683                  text: 'guest',
20684                  word: /^\s*\w*\s*$/
20685                };
20686              }]);
20687          </script>
20688          <form name="myForm" ng-controller="ExampleController">
20689            <label>Single word:
20690              <input type="text" name="input" ng-model="example.text"
20691                     ng-pattern="example.word" required ng-trim="false">
20692            </label>
20693            <div role="alert">
20694              <span class="error" ng-show="myForm.input.$error.required">
20695                Required!</span>
20696              <span class="error" ng-show="myForm.input.$error.pattern">
20697                Single word only!</span>
20698            </div>
20699            <tt>text = {{example.text}}</tt><br/>
20700            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20701            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20702            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20703            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20704           </form>
20705         </file>
20706         <file name="protractor.js" type="protractor">
20707           var text = element(by.binding('example.text'));
20708           var valid = element(by.binding('myForm.input.$valid'));
20709           var input = element(by.model('example.text'));
20710
20711           it('should initialize to model', function() {
20712             expect(text.getText()).toContain('guest');
20713             expect(valid.getText()).toContain('true');
20714           });
20715
20716           it('should be invalid if empty', function() {
20717             input.clear();
20718             input.sendKeys('');
20719
20720             expect(text.getText()).toEqual('text =');
20721             expect(valid.getText()).toContain('false');
20722           });
20723
20724           it('should be invalid if multi word', function() {
20725             input.clear();
20726             input.sendKeys('hello world');
20727
20728             expect(valid.getText()).toContain('false');
20729           });
20730         </file>
20731       </example>
20732    */
20733   'text': textInputType,
20734
20735     /**
20736      * @ngdoc input
20737      * @name input[date]
20738      *
20739      * @description
20740      * Input with date validation and transformation. In browsers that do not yet support
20741      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
20742      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
20743      * modern browsers do not yet support this input type, it is important to provide cues to users on the
20744      * expected input format via a placeholder or label.
20745      *
20746      * The model must always be a Date object, otherwise Angular will throw an error.
20747      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20748      *
20749      * The timezone to be used to read/write the `Date` instance in the model can be defined using
20750      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20751      *
20752      * @param {string} ngModel Assignable angular expression to data-bind to.
20753      * @param {string=} name Property name of the form under which the control is published.
20754      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20755      *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20756      *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
20757      *   constraint validation.
20758      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20759      *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20760      *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
20761      *   constraint validation.
20762      * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
20763      *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20764      * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
20765      *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20766      * @param {string=} required Sets `required` validation error key if the value is not entered.
20767      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20768      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20769      *    `required` when you want to data-bind to the `required` attribute.
20770      * @param {string=} ngChange Angular expression to be executed when input changes due to user
20771      *    interaction with the input element.
20772      *
20773      * @example
20774      <example name="date-input-directive" module="dateInputExample">
20775      <file name="index.html">
20776        <script>
20777           angular.module('dateInputExample', [])
20778             .controller('DateController', ['$scope', function($scope) {
20779               $scope.example = {
20780                 value: new Date(2013, 9, 22)
20781               };
20782             }]);
20783        </script>
20784        <form name="myForm" ng-controller="DateController as dateCtrl">
20785           <label for="exampleInput">Pick a date in 2013:</label>
20786           <input type="date" id="exampleInput" name="input" ng-model="example.value"
20787               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
20788           <div role="alert">
20789             <span class="error" ng-show="myForm.input.$error.required">
20790                 Required!</span>
20791             <span class="error" ng-show="myForm.input.$error.date">
20792                 Not a valid date!</span>
20793            </div>
20794            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
20795            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20796            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20797            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20798            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20799        </form>
20800      </file>
20801      <file name="protractor.js" type="protractor">
20802         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
20803         var valid = element(by.binding('myForm.input.$valid'));
20804         var input = element(by.model('example.value'));
20805
20806         // currently protractor/webdriver does not support
20807         // sending keys to all known HTML5 input controls
20808         // for various browsers (see https://github.com/angular/protractor/issues/562).
20809         function setInput(val) {
20810           // set the value of the element and force validation.
20811           var scr = "var ipt = document.getElementById('exampleInput'); " +
20812           "ipt.value = '" + val + "';" +
20813           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20814           browser.executeScript(scr);
20815         }
20816
20817         it('should initialize to model', function() {
20818           expect(value.getText()).toContain('2013-10-22');
20819           expect(valid.getText()).toContain('myForm.input.$valid = true');
20820         });
20821
20822         it('should be invalid if empty', function() {
20823           setInput('');
20824           expect(value.getText()).toEqual('value =');
20825           expect(valid.getText()).toContain('myForm.input.$valid = false');
20826         });
20827
20828         it('should be invalid if over max', function() {
20829           setInput('2015-01-01');
20830           expect(value.getText()).toContain('');
20831           expect(valid.getText()).toContain('myForm.input.$valid = false');
20832         });
20833      </file>
20834      </example>
20835      */
20836   'date': createDateInputType('date', DATE_REGEXP,
20837          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
20838          'yyyy-MM-dd'),
20839
20840    /**
20841     * @ngdoc input
20842     * @name input[datetime-local]
20843     *
20844     * @description
20845     * Input with datetime validation and transformation. In browsers that do not yet support
20846     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20847     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
20848     *
20849     * The model must always be a Date object, otherwise Angular will throw an error.
20850     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20851     *
20852     * The timezone to be used to read/write the `Date` instance in the model can be defined using
20853     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20854     *
20855     * @param {string} ngModel Assignable angular expression to data-bind to.
20856     * @param {string=} name Property name of the form under which the control is published.
20857     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20858     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20859     *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20860     *   Note that `min` will also add native HTML5 constraint validation.
20861     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20862     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20863     *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20864     *   Note that `max` will also add native HTML5 constraint validation.
20865     * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
20866     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20867     * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
20868     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20869     * @param {string=} required Sets `required` validation error key if the value is not entered.
20870     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20871     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20872     *    `required` when you want to data-bind to the `required` attribute.
20873     * @param {string=} ngChange Angular expression to be executed when input changes due to user
20874     *    interaction with the input element.
20875     *
20876     * @example
20877     <example name="datetimelocal-input-directive" module="dateExample">
20878     <file name="index.html">
20879       <script>
20880         angular.module('dateExample', [])
20881           .controller('DateController', ['$scope', function($scope) {
20882             $scope.example = {
20883               value: new Date(2010, 11, 28, 14, 57)
20884             };
20885           }]);
20886       </script>
20887       <form name="myForm" ng-controller="DateController as dateCtrl">
20888         <label for="exampleInput">Pick a date between in 2013:</label>
20889         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
20890             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
20891         <div role="alert">
20892           <span class="error" ng-show="myForm.input.$error.required">
20893               Required!</span>
20894           <span class="error" ng-show="myForm.input.$error.datetimelocal">
20895               Not a valid date!</span>
20896         </div>
20897         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
20898         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20899         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20900         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20901         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20902       </form>
20903     </file>
20904     <file name="protractor.js" type="protractor">
20905       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
20906       var valid = element(by.binding('myForm.input.$valid'));
20907       var input = element(by.model('example.value'));
20908
20909       // currently protractor/webdriver does not support
20910       // sending keys to all known HTML5 input controls
20911       // for various browsers (https://github.com/angular/protractor/issues/562).
20912       function setInput(val) {
20913         // set the value of the element and force validation.
20914         var scr = "var ipt = document.getElementById('exampleInput'); " +
20915         "ipt.value = '" + val + "';" +
20916         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20917         browser.executeScript(scr);
20918       }
20919
20920       it('should initialize to model', function() {
20921         expect(value.getText()).toContain('2010-12-28T14:57:00');
20922         expect(valid.getText()).toContain('myForm.input.$valid = true');
20923       });
20924
20925       it('should be invalid if empty', function() {
20926         setInput('');
20927         expect(value.getText()).toEqual('value =');
20928         expect(valid.getText()).toContain('myForm.input.$valid = false');
20929       });
20930
20931       it('should be invalid if over max', function() {
20932         setInput('2015-01-01T23:59:00');
20933         expect(value.getText()).toContain('');
20934         expect(valid.getText()).toContain('myForm.input.$valid = false');
20935       });
20936     </file>
20937     </example>
20938     */
20939   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
20940       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
20941       'yyyy-MM-ddTHH:mm:ss.sss'),
20942
20943   /**
20944    * @ngdoc input
20945    * @name input[time]
20946    *
20947    * @description
20948    * Input with time validation and transformation. In browsers that do not yet support
20949    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20950    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
20951    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
20952    *
20953    * The model must always be a Date object, otherwise Angular will throw an error.
20954    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20955    *
20956    * The timezone to be used to read/write the `Date` instance in the model can be defined using
20957    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20958    *
20959    * @param {string} ngModel Assignable angular expression to data-bind to.
20960    * @param {string=} name Property name of the form under which the control is published.
20961    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20962    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
20963    *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
20964    *   native HTML5 constraint validation.
20965    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20966    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
20967    *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
20968    *   native HTML5 constraint validation.
20969    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
20970    *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20971    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
20972    *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20973    * @param {string=} required Sets `required` validation error key if the value is not entered.
20974    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20975    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20976    *    `required` when you want to data-bind to the `required` attribute.
20977    * @param {string=} ngChange Angular expression to be executed when input changes due to user
20978    *    interaction with the input element.
20979    *
20980    * @example
20981    <example name="time-input-directive" module="timeExample">
20982    <file name="index.html">
20983      <script>
20984       angular.module('timeExample', [])
20985         .controller('DateController', ['$scope', function($scope) {
20986           $scope.example = {
20987             value: new Date(1970, 0, 1, 14, 57, 0)
20988           };
20989         }]);
20990      </script>
20991      <form name="myForm" ng-controller="DateController as dateCtrl">
20992         <label for="exampleInput">Pick a between 8am and 5pm:</label>
20993         <input type="time" id="exampleInput" name="input" ng-model="example.value"
20994             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
20995         <div role="alert">
20996           <span class="error" ng-show="myForm.input.$error.required">
20997               Required!</span>
20998           <span class="error" ng-show="myForm.input.$error.time">
20999               Not a valid date!</span>
21000         </div>
21001         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
21002         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21003         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21004         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21005         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21006      </form>
21007    </file>
21008    <file name="protractor.js" type="protractor">
21009       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
21010       var valid = element(by.binding('myForm.input.$valid'));
21011       var input = element(by.model('example.value'));
21012
21013       // currently protractor/webdriver does not support
21014       // sending keys to all known HTML5 input controls
21015       // for various browsers (https://github.com/angular/protractor/issues/562).
21016       function setInput(val) {
21017         // set the value of the element and force validation.
21018         var scr = "var ipt = document.getElementById('exampleInput'); " +
21019         "ipt.value = '" + val + "';" +
21020         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21021         browser.executeScript(scr);
21022       }
21023
21024       it('should initialize to model', function() {
21025         expect(value.getText()).toContain('14:57:00');
21026         expect(valid.getText()).toContain('myForm.input.$valid = true');
21027       });
21028
21029       it('should be invalid if empty', function() {
21030         setInput('');
21031         expect(value.getText()).toEqual('value =');
21032         expect(valid.getText()).toContain('myForm.input.$valid = false');
21033       });
21034
21035       it('should be invalid if over max', function() {
21036         setInput('23:59:00');
21037         expect(value.getText()).toContain('');
21038         expect(valid.getText()).toContain('myForm.input.$valid = false');
21039       });
21040    </file>
21041    </example>
21042    */
21043   'time': createDateInputType('time', TIME_REGEXP,
21044       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
21045      'HH:mm:ss.sss'),
21046
21047    /**
21048     * @ngdoc input
21049     * @name input[week]
21050     *
21051     * @description
21052     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
21053     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21054     * week format (yyyy-W##), for example: `2013-W02`.
21055     *
21056     * The model must always be a Date object, otherwise Angular will throw an error.
21057     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21058     *
21059     * The timezone to be used to read/write the `Date` instance in the model can be defined using
21060     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21061     *
21062     * @param {string} ngModel Assignable angular expression to data-bind to.
21063     * @param {string=} name Property name of the form under which the control is published.
21064     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21065     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21066     *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
21067     *   native HTML5 constraint validation.
21068     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21069     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21070     *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
21071     *   native HTML5 constraint validation.
21072     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21073     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21074     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21075     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21076     * @param {string=} required Sets `required` validation error key if the value is not entered.
21077     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21078     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21079     *    `required` when you want to data-bind to the `required` attribute.
21080     * @param {string=} ngChange Angular expression to be executed when input changes due to user
21081     *    interaction with the input element.
21082     *
21083     * @example
21084     <example name="week-input-directive" module="weekExample">
21085     <file name="index.html">
21086       <script>
21087       angular.module('weekExample', [])
21088         .controller('DateController', ['$scope', function($scope) {
21089           $scope.example = {
21090             value: new Date(2013, 0, 3)
21091           };
21092         }]);
21093       </script>
21094       <form name="myForm" ng-controller="DateController as dateCtrl">
21095         <label>Pick a date between in 2013:
21096           <input id="exampleInput" type="week" name="input" ng-model="example.value"
21097                  placeholder="YYYY-W##" min="2012-W32"
21098                  max="2013-W52" required />
21099         </label>
21100         <div role="alert">
21101           <span class="error" ng-show="myForm.input.$error.required">
21102               Required!</span>
21103           <span class="error" ng-show="myForm.input.$error.week">
21104               Not a valid date!</span>
21105         </div>
21106         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
21107         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21108         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21109         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21110         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21111       </form>
21112     </file>
21113     <file name="protractor.js" type="protractor">
21114       var value = element(by.binding('example.value | date: "yyyy-Www"'));
21115       var valid = element(by.binding('myForm.input.$valid'));
21116       var input = element(by.model('example.value'));
21117
21118       // currently protractor/webdriver does not support
21119       // sending keys to all known HTML5 input controls
21120       // for various browsers (https://github.com/angular/protractor/issues/562).
21121       function setInput(val) {
21122         // set the value of the element and force validation.
21123         var scr = "var ipt = document.getElementById('exampleInput'); " +
21124         "ipt.value = '" + val + "';" +
21125         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21126         browser.executeScript(scr);
21127       }
21128
21129       it('should initialize to model', function() {
21130         expect(value.getText()).toContain('2013-W01');
21131         expect(valid.getText()).toContain('myForm.input.$valid = true');
21132       });
21133
21134       it('should be invalid if empty', function() {
21135         setInput('');
21136         expect(value.getText()).toEqual('value =');
21137         expect(valid.getText()).toContain('myForm.input.$valid = false');
21138       });
21139
21140       it('should be invalid if over max', function() {
21141         setInput('2015-W01');
21142         expect(value.getText()).toContain('');
21143         expect(valid.getText()).toContain('myForm.input.$valid = false');
21144       });
21145     </file>
21146     </example>
21147     */
21148   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
21149
21150   /**
21151    * @ngdoc input
21152    * @name input[month]
21153    *
21154    * @description
21155    * Input with month validation and transformation. In browsers that do not yet support
21156    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21157    * month format (yyyy-MM), for example: `2009-01`.
21158    *
21159    * The model must always be a Date object, otherwise Angular will throw an error.
21160    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21161    * If the model is not set to the first of the month, the next view to model update will set it
21162    * to the first of the month.
21163    *
21164    * The timezone to be used to read/write the `Date` instance in the model can be defined using
21165    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21166    *
21167    * @param {string} ngModel Assignable angular expression to data-bind to.
21168    * @param {string=} name Property name of the form under which the control is published.
21169    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21170    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21171    *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
21172    *   native HTML5 constraint validation.
21173    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21174    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21175    *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
21176    *   native HTML5 constraint validation.
21177    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21178    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21179    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21180    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21181
21182    * @param {string=} required Sets `required` validation error key if the value is not entered.
21183    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21184    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21185    *    `required` when you want to data-bind to the `required` attribute.
21186    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21187    *    interaction with the input element.
21188    *
21189    * @example
21190    <example name="month-input-directive" module="monthExample">
21191    <file name="index.html">
21192      <script>
21193       angular.module('monthExample', [])
21194         .controller('DateController', ['$scope', function($scope) {
21195           $scope.example = {
21196             value: new Date(2013, 9, 1)
21197           };
21198         }]);
21199      </script>
21200      <form name="myForm" ng-controller="DateController as dateCtrl">
21201        <label for="exampleInput">Pick a month in 2013:</label>
21202        <input id="exampleInput" type="month" name="input" ng-model="example.value"
21203           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
21204        <div role="alert">
21205          <span class="error" ng-show="myForm.input.$error.required">
21206             Required!</span>
21207          <span class="error" ng-show="myForm.input.$error.month">
21208             Not a valid month!</span>
21209        </div>
21210        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
21211        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21212        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21213        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21214        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21215      </form>
21216    </file>
21217    <file name="protractor.js" type="protractor">
21218       var value = element(by.binding('example.value | date: "yyyy-MM"'));
21219       var valid = element(by.binding('myForm.input.$valid'));
21220       var input = element(by.model('example.value'));
21221
21222       // currently protractor/webdriver does not support
21223       // sending keys to all known HTML5 input controls
21224       // for various browsers (https://github.com/angular/protractor/issues/562).
21225       function setInput(val) {
21226         // set the value of the element and force validation.
21227         var scr = "var ipt = document.getElementById('exampleInput'); " +
21228         "ipt.value = '" + val + "';" +
21229         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21230         browser.executeScript(scr);
21231       }
21232
21233       it('should initialize to model', function() {
21234         expect(value.getText()).toContain('2013-10');
21235         expect(valid.getText()).toContain('myForm.input.$valid = true');
21236       });
21237
21238       it('should be invalid if empty', function() {
21239         setInput('');
21240         expect(value.getText()).toEqual('value =');
21241         expect(valid.getText()).toContain('myForm.input.$valid = false');
21242       });
21243
21244       it('should be invalid if over max', function() {
21245         setInput('2015-01');
21246         expect(value.getText()).toContain('');
21247         expect(valid.getText()).toContain('myForm.input.$valid = false');
21248       });
21249    </file>
21250    </example>
21251    */
21252   'month': createDateInputType('month', MONTH_REGEXP,
21253      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
21254      'yyyy-MM'),
21255
21256   /**
21257    * @ngdoc input
21258    * @name input[number]
21259    *
21260    * @description
21261    * Text input with number validation and transformation. Sets the `number` validation
21262    * error if not a valid number.
21263    *
21264    * <div class="alert alert-warning">
21265    * The model must always be of type `number` otherwise Angular will throw an error.
21266    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
21267    * error docs for more information and an example of how to convert your model if necessary.
21268    * </div>
21269    *
21270    * ## Issues with HTML5 constraint validation
21271    *
21272    * In browsers that follow the
21273    * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
21274    * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
21275    * If a non-number is entered in the input, the browser will report the value as an empty string,
21276    * which means the view / model values in `ngModel` and subsequently the scope value
21277    * will also be an empty string.
21278    *
21279    *
21280    * @param {string} ngModel Assignable angular expression to data-bind to.
21281    * @param {string=} name Property name of the form under which the control is published.
21282    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21283    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21284    * @param {string=} required Sets `required` validation error key if the value is not entered.
21285    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21286    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21287    *    `required` when you want to data-bind to the `required` attribute.
21288    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21289    *    minlength.
21290    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21291    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21292    *    any length.
21293    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21294    *    that contains the regular expression body that will be converted to a regular expression
21295    *    as in the ngPattern directive.
21296    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21297    *    a RegExp found by evaluating the Angular expression given in the attribute value.
21298    *    If the expression evaluates to a RegExp object, then this is used directly.
21299    *    If the expression evaluates to a string, then it will be converted to a RegExp
21300    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21301    *    `new RegExp('^abc$')`.<br />
21302    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21303    *    start at the index of the last search's match, thus not taking the whole input value into
21304    *    account.
21305    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21306    *    interaction with the input element.
21307    *
21308    * @example
21309       <example name="number-input-directive" module="numberExample">
21310         <file name="index.html">
21311          <script>
21312            angular.module('numberExample', [])
21313              .controller('ExampleController', ['$scope', function($scope) {
21314                $scope.example = {
21315                  value: 12
21316                };
21317              }]);
21318          </script>
21319          <form name="myForm" ng-controller="ExampleController">
21320            <label>Number:
21321              <input type="number" name="input" ng-model="example.value"
21322                     min="0" max="99" required>
21323           </label>
21324            <div role="alert">
21325              <span class="error" ng-show="myForm.input.$error.required">
21326                Required!</span>
21327              <span class="error" ng-show="myForm.input.$error.number">
21328                Not valid number!</span>
21329            </div>
21330            <tt>value = {{example.value}}</tt><br/>
21331            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21332            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21333            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21334            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21335           </form>
21336         </file>
21337         <file name="protractor.js" type="protractor">
21338           var value = element(by.binding('example.value'));
21339           var valid = element(by.binding('myForm.input.$valid'));
21340           var input = element(by.model('example.value'));
21341
21342           it('should initialize to model', function() {
21343             expect(value.getText()).toContain('12');
21344             expect(valid.getText()).toContain('true');
21345           });
21346
21347           it('should be invalid if empty', function() {
21348             input.clear();
21349             input.sendKeys('');
21350             expect(value.getText()).toEqual('value =');
21351             expect(valid.getText()).toContain('false');
21352           });
21353
21354           it('should be invalid if over max', function() {
21355             input.clear();
21356             input.sendKeys('123');
21357             expect(value.getText()).toEqual('value =');
21358             expect(valid.getText()).toContain('false');
21359           });
21360         </file>
21361       </example>
21362    */
21363   'number': numberInputType,
21364
21365
21366   /**
21367    * @ngdoc input
21368    * @name input[url]
21369    *
21370    * @description
21371    * Text input with URL validation. Sets the `url` validation error key if the content is not a
21372    * valid URL.
21373    *
21374    * <div class="alert alert-warning">
21375    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
21376    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
21377    * the built-in validators (see the {@link guide/forms Forms guide})
21378    * </div>
21379    *
21380    * @param {string} ngModel Assignable angular expression to data-bind to.
21381    * @param {string=} name Property name of the form under which the control is published.
21382    * @param {string=} required Sets `required` validation error key if the value is not entered.
21383    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21384    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21385    *    `required` when you want to data-bind to the `required` attribute.
21386    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21387    *    minlength.
21388    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21389    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21390    *    any length.
21391    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21392    *    that contains the regular expression body that will be converted to a regular expression
21393    *    as in the ngPattern directive.
21394    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21395    *    a RegExp found by evaluating the Angular expression given in the attribute value.
21396    *    If the expression evaluates to a RegExp object, then this is used directly.
21397    *    If the expression evaluates to a string, then it will be converted to a RegExp
21398    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21399    *    `new RegExp('^abc$')`.<br />
21400    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21401    *    start at the index of the last search's match, thus not taking the whole input value into
21402    *    account.
21403    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21404    *    interaction with the input element.
21405    *
21406    * @example
21407       <example name="url-input-directive" module="urlExample">
21408         <file name="index.html">
21409          <script>
21410            angular.module('urlExample', [])
21411              .controller('ExampleController', ['$scope', function($scope) {
21412                $scope.url = {
21413                  text: 'http://google.com'
21414                };
21415              }]);
21416          </script>
21417          <form name="myForm" ng-controller="ExampleController">
21418            <label>URL:
21419              <input type="url" name="input" ng-model="url.text" required>
21420            <label>
21421            <div role="alert">
21422              <span class="error" ng-show="myForm.input.$error.required">
21423                Required!</span>
21424              <span class="error" ng-show="myForm.input.$error.url">
21425                Not valid url!</span>
21426            </div>
21427            <tt>text = {{url.text}}</tt><br/>
21428            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21429            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21430            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21431            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21432            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
21433           </form>
21434         </file>
21435         <file name="protractor.js" type="protractor">
21436           var text = element(by.binding('url.text'));
21437           var valid = element(by.binding('myForm.input.$valid'));
21438           var input = element(by.model('url.text'));
21439
21440           it('should initialize to model', function() {
21441             expect(text.getText()).toContain('http://google.com');
21442             expect(valid.getText()).toContain('true');
21443           });
21444
21445           it('should be invalid if empty', function() {
21446             input.clear();
21447             input.sendKeys('');
21448
21449             expect(text.getText()).toEqual('text =');
21450             expect(valid.getText()).toContain('false');
21451           });
21452
21453           it('should be invalid if not url', function() {
21454             input.clear();
21455             input.sendKeys('box');
21456
21457             expect(valid.getText()).toContain('false');
21458           });
21459         </file>
21460       </example>
21461    */
21462   'url': urlInputType,
21463
21464
21465   /**
21466    * @ngdoc input
21467    * @name input[email]
21468    *
21469    * @description
21470    * Text input with email validation. Sets the `email` validation error key if not a valid email
21471    * address.
21472    *
21473    * <div class="alert alert-warning">
21474    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
21475    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
21476    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
21477    * </div>
21478    *
21479    * @param {string} ngModel Assignable angular expression to data-bind to.
21480    * @param {string=} name Property name of the form under which the control is published.
21481    * @param {string=} required Sets `required` validation error key if the value is not entered.
21482    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21483    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21484    *    `required` when you want to data-bind to the `required` attribute.
21485    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21486    *    minlength.
21487    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21488    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21489    *    any length.
21490    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21491    *    that contains the regular expression body that will be converted to a regular expression
21492    *    as in the ngPattern directive.
21493    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21494    *    a RegExp found by evaluating the Angular expression given in the attribute value.
21495    *    If the expression evaluates to a RegExp object, then this is used directly.
21496    *    If the expression evaluates to a string, then it will be converted to a RegExp
21497    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21498    *    `new RegExp('^abc$')`.<br />
21499    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21500    *    start at the index of the last search's match, thus not taking the whole input value into
21501    *    account.
21502    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21503    *    interaction with the input element.
21504    *
21505    * @example
21506       <example name="email-input-directive" module="emailExample">
21507         <file name="index.html">
21508          <script>
21509            angular.module('emailExample', [])
21510              .controller('ExampleController', ['$scope', function($scope) {
21511                $scope.email = {
21512                  text: 'me@example.com'
21513                };
21514              }]);
21515          </script>
21516            <form name="myForm" ng-controller="ExampleController">
21517              <label>Email:
21518                <input type="email" name="input" ng-model="email.text" required>
21519              </label>
21520              <div role="alert">
21521                <span class="error" ng-show="myForm.input.$error.required">
21522                  Required!</span>
21523                <span class="error" ng-show="myForm.input.$error.email">
21524                  Not valid email!</span>
21525              </div>
21526              <tt>text = {{email.text}}</tt><br/>
21527              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21528              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21529              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21530              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21531              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21532            </form>
21533          </file>
21534         <file name="protractor.js" type="protractor">
21535           var text = element(by.binding('email.text'));
21536           var valid = element(by.binding('myForm.input.$valid'));
21537           var input = element(by.model('email.text'));
21538
21539           it('should initialize to model', function() {
21540             expect(text.getText()).toContain('me@example.com');
21541             expect(valid.getText()).toContain('true');
21542           });
21543
21544           it('should be invalid if empty', function() {
21545             input.clear();
21546             input.sendKeys('');
21547             expect(text.getText()).toEqual('text =');
21548             expect(valid.getText()).toContain('false');
21549           });
21550
21551           it('should be invalid if not email', function() {
21552             input.clear();
21553             input.sendKeys('xxx');
21554
21555             expect(valid.getText()).toContain('false');
21556           });
21557         </file>
21558       </example>
21559    */
21560   'email': emailInputType,
21561
21562
21563   /**
21564    * @ngdoc input
21565    * @name input[radio]
21566    *
21567    * @description
21568    * HTML radio button.
21569    *
21570    * @param {string} ngModel Assignable angular expression to data-bind to.
21571    * @param {string} value The value to which the `ngModel` expression should be set when selected.
21572    *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
21573    *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
21574    * @param {string=} name Property name of the form under which the control is published.
21575    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21576    *    interaction with the input element.
21577    * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
21578    *    is selected. Should be used instead of the `value` attribute if you need
21579    *    a non-string `ngModel` (`boolean`, `array`, ...).
21580    *
21581    * @example
21582       <example name="radio-input-directive" module="radioExample">
21583         <file name="index.html">
21584          <script>
21585            angular.module('radioExample', [])
21586              .controller('ExampleController', ['$scope', function($scope) {
21587                $scope.color = {
21588                  name: 'blue'
21589                };
21590                $scope.specialValue = {
21591                  "id": "12345",
21592                  "value": "green"
21593                };
21594              }]);
21595          </script>
21596          <form name="myForm" ng-controller="ExampleController">
21597            <label>
21598              <input type="radio" ng-model="color.name" value="red">
21599              Red
21600            </label><br/>
21601            <label>
21602              <input type="radio" ng-model="color.name" ng-value="specialValue">
21603              Green
21604            </label><br/>
21605            <label>
21606              <input type="radio" ng-model="color.name" value="blue">
21607              Blue
21608            </label><br/>
21609            <tt>color = {{color.name | json}}</tt><br/>
21610           </form>
21611           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21612         </file>
21613         <file name="protractor.js" type="protractor">
21614           it('should change state', function() {
21615             var color = element(by.binding('color.name'));
21616
21617             expect(color.getText()).toContain('blue');
21618
21619             element.all(by.model('color.name')).get(0).click();
21620
21621             expect(color.getText()).toContain('red');
21622           });
21623         </file>
21624       </example>
21625    */
21626   'radio': radioInputType,
21627
21628
21629   /**
21630    * @ngdoc input
21631    * @name input[checkbox]
21632    *
21633    * @description
21634    * HTML checkbox.
21635    *
21636    * @param {string} ngModel Assignable angular expression to data-bind to.
21637    * @param {string=} name Property name of the form under which the control is published.
21638    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
21639    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
21640    * @param {string=} ngChange Angular expression to be executed when input changes due to user
21641    *    interaction with the input element.
21642    *
21643    * @example
21644       <example name="checkbox-input-directive" module="checkboxExample">
21645         <file name="index.html">
21646          <script>
21647            angular.module('checkboxExample', [])
21648              .controller('ExampleController', ['$scope', function($scope) {
21649                $scope.checkboxModel = {
21650                 value1 : true,
21651                 value2 : 'YES'
21652               };
21653              }]);
21654          </script>
21655          <form name="myForm" ng-controller="ExampleController">
21656            <label>Value1:
21657              <input type="checkbox" ng-model="checkboxModel.value1">
21658            </label><br/>
21659            <label>Value2:
21660              <input type="checkbox" ng-model="checkboxModel.value2"
21661                     ng-true-value="'YES'" ng-false-value="'NO'">
21662             </label><br/>
21663            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
21664            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
21665           </form>
21666         </file>
21667         <file name="protractor.js" type="protractor">
21668           it('should change state', function() {
21669             var value1 = element(by.binding('checkboxModel.value1'));
21670             var value2 = element(by.binding('checkboxModel.value2'));
21671
21672             expect(value1.getText()).toContain('true');
21673             expect(value2.getText()).toContain('YES');
21674
21675             element(by.model('checkboxModel.value1')).click();
21676             element(by.model('checkboxModel.value2')).click();
21677
21678             expect(value1.getText()).toContain('false');
21679             expect(value2.getText()).toContain('NO');
21680           });
21681         </file>
21682       </example>
21683    */
21684   'checkbox': checkboxInputType,
21685
21686   'hidden': noop,
21687   'button': noop,
21688   'submit': noop,
21689   'reset': noop,
21690   'file': noop
21691 };
21692
21693 function stringBasedInputType(ctrl) {
21694   ctrl.$formatters.push(function(value) {
21695     return ctrl.$isEmpty(value) ? value : value.toString();
21696   });
21697 }
21698
21699 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21700   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21701   stringBasedInputType(ctrl);
21702 }
21703
21704 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21705   var type = lowercase(element[0].type);
21706
21707   // In composition mode, users are still inputing intermediate text buffer,
21708   // hold the listener until composition is done.
21709   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
21710   if (!$sniffer.android) {
21711     var composing = false;
21712
21713     element.on('compositionstart', function(data) {
21714       composing = true;
21715     });
21716
21717     element.on('compositionend', function() {
21718       composing = false;
21719       listener();
21720     });
21721   }
21722
21723   var listener = function(ev) {
21724     if (timeout) {
21725       $browser.defer.cancel(timeout);
21726       timeout = null;
21727     }
21728     if (composing) return;
21729     var value = element.val(),
21730         event = ev && ev.type;
21731
21732     // By default we will trim the value
21733     // If the attribute ng-trim exists we will avoid trimming
21734     // If input type is 'password', the value is never trimmed
21735     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
21736       value = trim(value);
21737     }
21738
21739     // If a control is suffering from bad input (due to native validators), browsers discard its
21740     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
21741     // control's value is the same empty value twice in a row.
21742     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
21743       ctrl.$setViewValue(value, event);
21744     }
21745   };
21746
21747   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
21748   // input event on backspace, delete or cut
21749   if ($sniffer.hasEvent('input')) {
21750     element.on('input', listener);
21751   } else {
21752     var timeout;
21753
21754     var deferListener = function(ev, input, origValue) {
21755       if (!timeout) {
21756         timeout = $browser.defer(function() {
21757           timeout = null;
21758           if (!input || input.value !== origValue) {
21759             listener(ev);
21760           }
21761         });
21762       }
21763     };
21764
21765     element.on('keydown', function(event) {
21766       var key = event.keyCode;
21767
21768       // ignore
21769       //    command            modifiers                   arrows
21770       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
21771
21772       deferListener(event, this, this.value);
21773     });
21774
21775     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
21776     if ($sniffer.hasEvent('paste')) {
21777       element.on('paste cut', deferListener);
21778     }
21779   }
21780
21781   // if user paste into input using mouse on older browser
21782   // or form autocomplete on newer browser, we need "change" event to catch it
21783   element.on('change', listener);
21784
21785   ctrl.$render = function() {
21786     // Workaround for Firefox validation #12102.
21787     var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
21788     if (element.val() !== value) {
21789       element.val(value);
21790     }
21791   };
21792 }
21793
21794 function weekParser(isoWeek, existingDate) {
21795   if (isDate(isoWeek)) {
21796     return isoWeek;
21797   }
21798
21799   if (isString(isoWeek)) {
21800     WEEK_REGEXP.lastIndex = 0;
21801     var parts = WEEK_REGEXP.exec(isoWeek);
21802     if (parts) {
21803       var year = +parts[1],
21804           week = +parts[2],
21805           hours = 0,
21806           minutes = 0,
21807           seconds = 0,
21808           milliseconds = 0,
21809           firstThurs = getFirstThursdayOfYear(year),
21810           addDays = (week - 1) * 7;
21811
21812       if (existingDate) {
21813         hours = existingDate.getHours();
21814         minutes = existingDate.getMinutes();
21815         seconds = existingDate.getSeconds();
21816         milliseconds = existingDate.getMilliseconds();
21817       }
21818
21819       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
21820     }
21821   }
21822
21823   return NaN;
21824 }
21825
21826 function createDateParser(regexp, mapping) {
21827   return function(iso, date) {
21828     var parts, map;
21829
21830     if (isDate(iso)) {
21831       return iso;
21832     }
21833
21834     if (isString(iso)) {
21835       // When a date is JSON'ified to wraps itself inside of an extra
21836       // set of double quotes. This makes the date parsing code unable
21837       // to match the date string and parse it as a date.
21838       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
21839         iso = iso.substring(1, iso.length - 1);
21840       }
21841       if (ISO_DATE_REGEXP.test(iso)) {
21842         return new Date(iso);
21843       }
21844       regexp.lastIndex = 0;
21845       parts = regexp.exec(iso);
21846
21847       if (parts) {
21848         parts.shift();
21849         if (date) {
21850           map = {
21851             yyyy: date.getFullYear(),
21852             MM: date.getMonth() + 1,
21853             dd: date.getDate(),
21854             HH: date.getHours(),
21855             mm: date.getMinutes(),
21856             ss: date.getSeconds(),
21857             sss: date.getMilliseconds() / 1000
21858           };
21859         } else {
21860           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
21861         }
21862
21863         forEach(parts, function(part, index) {
21864           if (index < mapping.length) {
21865             map[mapping[index]] = +part;
21866           }
21867         });
21868         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
21869       }
21870     }
21871
21872     return NaN;
21873   };
21874 }
21875
21876 function createDateInputType(type, regexp, parseDate, format) {
21877   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
21878     badInputChecker(scope, element, attr, ctrl);
21879     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21880     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
21881     var previousDate;
21882
21883     ctrl.$$parserName = type;
21884     ctrl.$parsers.push(function(value) {
21885       if (ctrl.$isEmpty(value)) return null;
21886       if (regexp.test(value)) {
21887         // Note: We cannot read ctrl.$modelValue, as there might be a different
21888         // parser/formatter in the processing chain so that the model
21889         // contains some different data format!
21890         var parsedDate = parseDate(value, previousDate);
21891         if (timezone) {
21892           parsedDate = convertTimezoneToLocal(parsedDate, timezone);
21893         }
21894         return parsedDate;
21895       }
21896       return undefined;
21897     });
21898
21899     ctrl.$formatters.push(function(value) {
21900       if (value && !isDate(value)) {
21901         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
21902       }
21903       if (isValidDate(value)) {
21904         previousDate = value;
21905         if (previousDate && timezone) {
21906           previousDate = convertTimezoneToLocal(previousDate, timezone, true);
21907         }
21908         return $filter('date')(value, format, timezone);
21909       } else {
21910         previousDate = null;
21911         return '';
21912       }
21913     });
21914
21915     if (isDefined(attr.min) || attr.ngMin) {
21916       var minVal;
21917       ctrl.$validators.min = function(value) {
21918         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
21919       };
21920       attr.$observe('min', function(val) {
21921         minVal = parseObservedDateValue(val);
21922         ctrl.$validate();
21923       });
21924     }
21925
21926     if (isDefined(attr.max) || attr.ngMax) {
21927       var maxVal;
21928       ctrl.$validators.max = function(value) {
21929         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
21930       };
21931       attr.$observe('max', function(val) {
21932         maxVal = parseObservedDateValue(val);
21933         ctrl.$validate();
21934       });
21935     }
21936
21937     function isValidDate(value) {
21938       // Invalid Date: getTime() returns NaN
21939       return value && !(value.getTime && value.getTime() !== value.getTime());
21940     }
21941
21942     function parseObservedDateValue(val) {
21943       return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
21944     }
21945   };
21946 }
21947
21948 function badInputChecker(scope, element, attr, ctrl) {
21949   var node = element[0];
21950   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
21951   if (nativeValidation) {
21952     ctrl.$parsers.push(function(value) {
21953       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
21954       // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
21955       // - also sets validity.badInput (should only be validity.typeMismatch).
21956       // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
21957       // - can ignore this case as we can still read out the erroneous email...
21958       return validity.badInput && !validity.typeMismatch ? undefined : value;
21959     });
21960   }
21961 }
21962
21963 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21964   badInputChecker(scope, element, attr, ctrl);
21965   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21966
21967   ctrl.$$parserName = 'number';
21968   ctrl.$parsers.push(function(value) {
21969     if (ctrl.$isEmpty(value))      return null;
21970     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
21971     return undefined;
21972   });
21973
21974   ctrl.$formatters.push(function(value) {
21975     if (!ctrl.$isEmpty(value)) {
21976       if (!isNumber(value)) {
21977         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
21978       }
21979       value = value.toString();
21980     }
21981     return value;
21982   });
21983
21984   if (isDefined(attr.min) || attr.ngMin) {
21985     var minVal;
21986     ctrl.$validators.min = function(value) {
21987       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
21988     };
21989
21990     attr.$observe('min', function(val) {
21991       if (isDefined(val) && !isNumber(val)) {
21992         val = parseFloat(val, 10);
21993       }
21994       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
21995       // TODO(matsko): implement validateLater to reduce number of validations
21996       ctrl.$validate();
21997     });
21998   }
21999
22000   if (isDefined(attr.max) || attr.ngMax) {
22001     var maxVal;
22002     ctrl.$validators.max = function(value) {
22003       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
22004     };
22005
22006     attr.$observe('max', function(val) {
22007       if (isDefined(val) && !isNumber(val)) {
22008         val = parseFloat(val, 10);
22009       }
22010       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
22011       // TODO(matsko): implement validateLater to reduce number of validations
22012       ctrl.$validate();
22013     });
22014   }
22015 }
22016
22017 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22018   // Note: no badInputChecker here by purpose as `url` is only a validation
22019   // in browsers, i.e. we can always read out input.value even if it is not valid!
22020   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22021   stringBasedInputType(ctrl);
22022
22023   ctrl.$$parserName = 'url';
22024   ctrl.$validators.url = function(modelValue, viewValue) {
22025     var value = modelValue || viewValue;
22026     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
22027   };
22028 }
22029
22030 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22031   // Note: no badInputChecker here by purpose as `url` is only a validation
22032   // in browsers, i.e. we can always read out input.value even if it is not valid!
22033   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22034   stringBasedInputType(ctrl);
22035
22036   ctrl.$$parserName = 'email';
22037   ctrl.$validators.email = function(modelValue, viewValue) {
22038     var value = modelValue || viewValue;
22039     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
22040   };
22041 }
22042
22043 function radioInputType(scope, element, attr, ctrl) {
22044   // make the name unique, if not defined
22045   if (isUndefined(attr.name)) {
22046     element.attr('name', nextUid());
22047   }
22048
22049   var listener = function(ev) {
22050     if (element[0].checked) {
22051       ctrl.$setViewValue(attr.value, ev && ev.type);
22052     }
22053   };
22054
22055   element.on('click', listener);
22056
22057   ctrl.$render = function() {
22058     var value = attr.value;
22059     element[0].checked = (value == ctrl.$viewValue);
22060   };
22061
22062   attr.$observe('value', ctrl.$render);
22063 }
22064
22065 function parseConstantExpr($parse, context, name, expression, fallback) {
22066   var parseFn;
22067   if (isDefined(expression)) {
22068     parseFn = $parse(expression);
22069     if (!parseFn.constant) {
22070       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
22071                                    '`{1}`.', name, expression);
22072     }
22073     return parseFn(context);
22074   }
22075   return fallback;
22076 }
22077
22078 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
22079   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
22080   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
22081
22082   var listener = function(ev) {
22083     ctrl.$setViewValue(element[0].checked, ev && ev.type);
22084   };
22085
22086   element.on('click', listener);
22087
22088   ctrl.$render = function() {
22089     element[0].checked = ctrl.$viewValue;
22090   };
22091
22092   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
22093   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
22094   // it to a boolean.
22095   ctrl.$isEmpty = function(value) {
22096     return value === false;
22097   };
22098
22099   ctrl.$formatters.push(function(value) {
22100     return equals(value, trueValue);
22101   });
22102
22103   ctrl.$parsers.push(function(value) {
22104     return value ? trueValue : falseValue;
22105   });
22106 }
22107
22108
22109 /**
22110  * @ngdoc directive
22111  * @name textarea
22112  * @restrict E
22113  *
22114  * @description
22115  * HTML textarea element control with angular data-binding. The data-binding and validation
22116  * properties of this element are exactly the same as those of the
22117  * {@link ng.directive:input input element}.
22118  *
22119  * @param {string} ngModel Assignable angular expression to data-bind to.
22120  * @param {string=} name Property name of the form under which the control is published.
22121  * @param {string=} required Sets `required` validation error key if the value is not entered.
22122  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
22123  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
22124  *    `required` when you want to data-bind to the `required` attribute.
22125  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22126  *    minlength.
22127  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22128  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22129  *    length.
22130  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22131  *    a RegExp found by evaluating the Angular expression given in the attribute value.
22132  *    If the expression evaluates to a RegExp object, then this is used directly.
22133  *    If the expression evaluates to a string, then it will be converted to a RegExp
22134  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22135  *    `new RegExp('^abc$')`.<br />
22136  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22137  *    start at the index of the last search's match, thus not taking the whole input value into
22138  *    account.
22139  * @param {string=} ngChange Angular expression to be executed when input changes due to user
22140  *    interaction with the input element.
22141  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22142  */
22143
22144
22145 /**
22146  * @ngdoc directive
22147  * @name input
22148  * @restrict E
22149  *
22150  * @description
22151  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
22152  * input state control, and validation.
22153  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
22154  *
22155  * <div class="alert alert-warning">
22156  * **Note:** Not every feature offered is available for all input types.
22157  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
22158  * </div>
22159  *
22160  * @param {string} ngModel Assignable angular expression to data-bind to.
22161  * @param {string=} name Property name of the form under which the control is published.
22162  * @param {string=} required Sets `required` validation error key if the value is not entered.
22163  * @param {boolean=} ngRequired Sets `required` attribute if set to true
22164  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22165  *    minlength.
22166  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22167  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22168  *    length.
22169  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22170  *    a RegExp found by evaluating the Angular expression given in the attribute value.
22171  *    If the expression evaluates to a RegExp object, then this is used directly.
22172  *    If the expression evaluates to a string, then it will be converted to a RegExp
22173  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22174  *    `new RegExp('^abc$')`.<br />
22175  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22176  *    start at the index of the last search's match, thus not taking the whole input value into
22177  *    account.
22178  * @param {string=} ngChange Angular expression to be executed when input changes due to user
22179  *    interaction with the input element.
22180  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22181  *    This parameter is ignored for input[type=password] controls, which will never trim the
22182  *    input.
22183  *
22184  * @example
22185     <example name="input-directive" module="inputExample">
22186       <file name="index.html">
22187        <script>
22188           angular.module('inputExample', [])
22189             .controller('ExampleController', ['$scope', function($scope) {
22190               $scope.user = {name: 'guest', last: 'visitor'};
22191             }]);
22192        </script>
22193        <div ng-controller="ExampleController">
22194          <form name="myForm">
22195            <label>
22196               User name:
22197               <input type="text" name="userName" ng-model="user.name" required>
22198            </label>
22199            <div role="alert">
22200              <span class="error" ng-show="myForm.userName.$error.required">
22201               Required!</span>
22202            </div>
22203            <label>
22204               Last name:
22205               <input type="text" name="lastName" ng-model="user.last"
22206               ng-minlength="3" ng-maxlength="10">
22207            </label>
22208            <div role="alert">
22209              <span class="error" ng-show="myForm.lastName.$error.minlength">
22210                Too short!</span>
22211              <span class="error" ng-show="myForm.lastName.$error.maxlength">
22212                Too long!</span>
22213            </div>
22214          </form>
22215          <hr>
22216          <tt>user = {{user}}</tt><br/>
22217          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
22218          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
22219          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
22220          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
22221          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22222          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22223          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
22224          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
22225        </div>
22226       </file>
22227       <file name="protractor.js" type="protractor">
22228         var user = element(by.exactBinding('user'));
22229         var userNameValid = element(by.binding('myForm.userName.$valid'));
22230         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
22231         var lastNameError = element(by.binding('myForm.lastName.$error'));
22232         var formValid = element(by.binding('myForm.$valid'));
22233         var userNameInput = element(by.model('user.name'));
22234         var userLastInput = element(by.model('user.last'));
22235
22236         it('should initialize to model', function() {
22237           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
22238           expect(userNameValid.getText()).toContain('true');
22239           expect(formValid.getText()).toContain('true');
22240         });
22241
22242         it('should be invalid if empty when required', function() {
22243           userNameInput.clear();
22244           userNameInput.sendKeys('');
22245
22246           expect(user.getText()).toContain('{"last":"visitor"}');
22247           expect(userNameValid.getText()).toContain('false');
22248           expect(formValid.getText()).toContain('false');
22249         });
22250
22251         it('should be valid if empty when min length is set', function() {
22252           userLastInput.clear();
22253           userLastInput.sendKeys('');
22254
22255           expect(user.getText()).toContain('{"name":"guest","last":""}');
22256           expect(lastNameValid.getText()).toContain('true');
22257           expect(formValid.getText()).toContain('true');
22258         });
22259
22260         it('should be invalid if less than required min length', function() {
22261           userLastInput.clear();
22262           userLastInput.sendKeys('xx');
22263
22264           expect(user.getText()).toContain('{"name":"guest"}');
22265           expect(lastNameValid.getText()).toContain('false');
22266           expect(lastNameError.getText()).toContain('minlength');
22267           expect(formValid.getText()).toContain('false');
22268         });
22269
22270         it('should be invalid if longer than max length', function() {
22271           userLastInput.clear();
22272           userLastInput.sendKeys('some ridiculously long name');
22273
22274           expect(user.getText()).toContain('{"name":"guest"}');
22275           expect(lastNameValid.getText()).toContain('false');
22276           expect(lastNameError.getText()).toContain('maxlength');
22277           expect(formValid.getText()).toContain('false');
22278         });
22279       </file>
22280     </example>
22281  */
22282 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
22283     function($browser, $sniffer, $filter, $parse) {
22284   return {
22285     restrict: 'E',
22286     require: ['?ngModel'],
22287     link: {
22288       pre: function(scope, element, attr, ctrls) {
22289         if (ctrls[0]) {
22290           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
22291                                                               $browser, $filter, $parse);
22292         }
22293       }
22294     }
22295   };
22296 }];
22297
22298
22299
22300 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
22301 /**
22302  * @ngdoc directive
22303  * @name ngValue
22304  *
22305  * @description
22306  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
22307  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
22308  * the bound value.
22309  *
22310  * `ngValue` is useful when dynamically generating lists of radio buttons using
22311  * {@link ngRepeat `ngRepeat`}, as shown below.
22312  *
22313  * Likewise, `ngValue` can be used to generate `<option>` elements for
22314  * the {@link select `select`} element. In that case however, only strings are supported
22315  * for the `value `attribute, so the resulting `ngModel` will always be a string.
22316  * Support for `select` models with non-string values is available via `ngOptions`.
22317  *
22318  * @element input
22319  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
22320  *   of the `input` element
22321  *
22322  * @example
22323     <example name="ngValue-directive" module="valueExample">
22324       <file name="index.html">
22325        <script>
22326           angular.module('valueExample', [])
22327             .controller('ExampleController', ['$scope', function($scope) {
22328               $scope.names = ['pizza', 'unicorns', 'robots'];
22329               $scope.my = { favorite: 'unicorns' };
22330             }]);
22331        </script>
22332         <form ng-controller="ExampleController">
22333           <h2>Which is your favorite?</h2>
22334             <label ng-repeat="name in names" for="{{name}}">
22335               {{name}}
22336               <input type="radio"
22337                      ng-model="my.favorite"
22338                      ng-value="name"
22339                      id="{{name}}"
22340                      name="favorite">
22341             </label>
22342           <div>You chose {{my.favorite}}</div>
22343         </form>
22344       </file>
22345       <file name="protractor.js" type="protractor">
22346         var favorite = element(by.binding('my.favorite'));
22347
22348         it('should initialize to model', function() {
22349           expect(favorite.getText()).toContain('unicorns');
22350         });
22351         it('should bind the values to the inputs', function() {
22352           element.all(by.model('my.favorite')).get(0).click();
22353           expect(favorite.getText()).toContain('pizza');
22354         });
22355       </file>
22356     </example>
22357  */
22358 var ngValueDirective = function() {
22359   return {
22360     restrict: 'A',
22361     priority: 100,
22362     compile: function(tpl, tplAttr) {
22363       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
22364         return function ngValueConstantLink(scope, elm, attr) {
22365           attr.$set('value', scope.$eval(attr.ngValue));
22366         };
22367       } else {
22368         return function ngValueLink(scope, elm, attr) {
22369           scope.$watch(attr.ngValue, function valueWatchAction(value) {
22370             attr.$set('value', value);
22371           });
22372         };
22373       }
22374     }
22375   };
22376 };
22377
22378 /**
22379  * @ngdoc directive
22380  * @name ngBind
22381  * @restrict AC
22382  *
22383  * @description
22384  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
22385  * with the value of a given expression, and to update the text content when the value of that
22386  * expression changes.
22387  *
22388  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
22389  * `{{ expression }}` which is similar but less verbose.
22390  *
22391  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
22392  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
22393  * element attribute, it makes the bindings invisible to the user while the page is loading.
22394  *
22395  * An alternative solution to this problem would be using the
22396  * {@link ng.directive:ngCloak ngCloak} directive.
22397  *
22398  *
22399  * @element ANY
22400  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
22401  *
22402  * @example
22403  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
22404    <example module="bindExample">
22405      <file name="index.html">
22406        <script>
22407          angular.module('bindExample', [])
22408            .controller('ExampleController', ['$scope', function($scope) {
22409              $scope.name = 'Whirled';
22410            }]);
22411        </script>
22412        <div ng-controller="ExampleController">
22413          <label>Enter name: <input type="text" ng-model="name"></label><br>
22414          Hello <span ng-bind="name"></span>!
22415        </div>
22416      </file>
22417      <file name="protractor.js" type="protractor">
22418        it('should check ng-bind', function() {
22419          var nameInput = element(by.model('name'));
22420
22421          expect(element(by.binding('name')).getText()).toBe('Whirled');
22422          nameInput.clear();
22423          nameInput.sendKeys('world');
22424          expect(element(by.binding('name')).getText()).toBe('world');
22425        });
22426      </file>
22427    </example>
22428  */
22429 var ngBindDirective = ['$compile', function($compile) {
22430   return {
22431     restrict: 'AC',
22432     compile: function ngBindCompile(templateElement) {
22433       $compile.$$addBindingClass(templateElement);
22434       return function ngBindLink(scope, element, attr) {
22435         $compile.$$addBindingInfo(element, attr.ngBind);
22436         element = element[0];
22437         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
22438           element.textContent = isUndefined(value) ? '' : value;
22439         });
22440       };
22441     }
22442   };
22443 }];
22444
22445
22446 /**
22447  * @ngdoc directive
22448  * @name ngBindTemplate
22449  *
22450  * @description
22451  * The `ngBindTemplate` directive specifies that the element
22452  * text content should be replaced with the interpolation of the template
22453  * in the `ngBindTemplate` attribute.
22454  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
22455  * expressions. This directive is needed since some HTML elements
22456  * (such as TITLE and OPTION) cannot contain SPAN elements.
22457  *
22458  * @element ANY
22459  * @param {string} ngBindTemplate template of form
22460  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
22461  *
22462  * @example
22463  * Try it here: enter text in text box and watch the greeting change.
22464    <example module="bindExample">
22465      <file name="index.html">
22466        <script>
22467          angular.module('bindExample', [])
22468            .controller('ExampleController', ['$scope', function($scope) {
22469              $scope.salutation = 'Hello';
22470              $scope.name = 'World';
22471            }]);
22472        </script>
22473        <div ng-controller="ExampleController">
22474         <label>Salutation: <input type="text" ng-model="salutation"></label><br>
22475         <label>Name: <input type="text" ng-model="name"></label><br>
22476         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
22477        </div>
22478      </file>
22479      <file name="protractor.js" type="protractor">
22480        it('should check ng-bind', function() {
22481          var salutationElem = element(by.binding('salutation'));
22482          var salutationInput = element(by.model('salutation'));
22483          var nameInput = element(by.model('name'));
22484
22485          expect(salutationElem.getText()).toBe('Hello World!');
22486
22487          salutationInput.clear();
22488          salutationInput.sendKeys('Greetings');
22489          nameInput.clear();
22490          nameInput.sendKeys('user');
22491
22492          expect(salutationElem.getText()).toBe('Greetings user!');
22493        });
22494      </file>
22495    </example>
22496  */
22497 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
22498   return {
22499     compile: function ngBindTemplateCompile(templateElement) {
22500       $compile.$$addBindingClass(templateElement);
22501       return function ngBindTemplateLink(scope, element, attr) {
22502         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
22503         $compile.$$addBindingInfo(element, interpolateFn.expressions);
22504         element = element[0];
22505         attr.$observe('ngBindTemplate', function(value) {
22506           element.textContent = isUndefined(value) ? '' : value;
22507         });
22508       };
22509     }
22510   };
22511 }];
22512
22513
22514 /**
22515  * @ngdoc directive
22516  * @name ngBindHtml
22517  *
22518  * @description
22519  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
22520  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
22521  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
22522  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
22523  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
22524  *
22525  * You may also bypass sanitization for values you know are safe. To do so, bind to
22526  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
22527  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
22528  *
22529  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
22530  * will have an exception (instead of an exploit.)
22531  *
22532  * @element ANY
22533  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
22534  *
22535  * @example
22536
22537    <example module="bindHtmlExample" deps="angular-sanitize.js">
22538      <file name="index.html">
22539        <div ng-controller="ExampleController">
22540         <p ng-bind-html="myHTML"></p>
22541        </div>
22542      </file>
22543
22544      <file name="script.js">
22545        angular.module('bindHtmlExample', ['ngSanitize'])
22546          .controller('ExampleController', ['$scope', function($scope) {
22547            $scope.myHTML =
22548               'I am an <code>HTML</code>string with ' +
22549               '<a href="#">links!</a> and other <em>stuff</em>';
22550          }]);
22551      </file>
22552
22553      <file name="protractor.js" type="protractor">
22554        it('should check ng-bind-html', function() {
22555          expect(element(by.binding('myHTML')).getText()).toBe(
22556              'I am an HTMLstring with links! and other stuff');
22557        });
22558      </file>
22559    </example>
22560  */
22561 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
22562   return {
22563     restrict: 'A',
22564     compile: function ngBindHtmlCompile(tElement, tAttrs) {
22565       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
22566       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
22567         return (value || '').toString();
22568       });
22569       $compile.$$addBindingClass(tElement);
22570
22571       return function ngBindHtmlLink(scope, element, attr) {
22572         $compile.$$addBindingInfo(element, attr.ngBindHtml);
22573
22574         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
22575           // we re-evaluate the expr because we want a TrustedValueHolderType
22576           // for $sce, not a string
22577           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
22578         });
22579       };
22580     }
22581   };
22582 }];
22583
22584 /**
22585  * @ngdoc directive
22586  * @name ngChange
22587  *
22588  * @description
22589  * Evaluate the given expression when the user changes the input.
22590  * The expression is evaluated immediately, unlike the JavaScript onchange event
22591  * which only triggers at the end of a change (usually, when the user leaves the
22592  * form element or presses the return key).
22593  *
22594  * The `ngChange` expression is only evaluated when a change in the input value causes
22595  * a new value to be committed to the model.
22596  *
22597  * It will not be evaluated:
22598  * * if the value returned from the `$parsers` transformation pipeline has not changed
22599  * * if the input has continued to be invalid since the model will stay `null`
22600  * * if the model is changed programmatically and not by a change to the input value
22601  *
22602  *
22603  * Note, this directive requires `ngModel` to be present.
22604  *
22605  * @element input
22606  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22607  * in input value.
22608  *
22609  * @example
22610  * <example name="ngChange-directive" module="changeExample">
22611  *   <file name="index.html">
22612  *     <script>
22613  *       angular.module('changeExample', [])
22614  *         .controller('ExampleController', ['$scope', function($scope) {
22615  *           $scope.counter = 0;
22616  *           $scope.change = function() {
22617  *             $scope.counter++;
22618  *           };
22619  *         }]);
22620  *     </script>
22621  *     <div ng-controller="ExampleController">
22622  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22623  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22624  *       <label for="ng-change-example2">Confirmed</label><br />
22625  *       <tt>debug = {{confirmed}}</tt><br/>
22626  *       <tt>counter = {{counter}}</tt><br/>
22627  *     </div>
22628  *   </file>
22629  *   <file name="protractor.js" type="protractor">
22630  *     var counter = element(by.binding('counter'));
22631  *     var debug = element(by.binding('confirmed'));
22632  *
22633  *     it('should evaluate the expression if changing from view', function() {
22634  *       expect(counter.getText()).toContain('0');
22635  *
22636  *       element(by.id('ng-change-example1')).click();
22637  *
22638  *       expect(counter.getText()).toContain('1');
22639  *       expect(debug.getText()).toContain('true');
22640  *     });
22641  *
22642  *     it('should not evaluate the expression if changing from model', function() {
22643  *       element(by.id('ng-change-example2')).click();
22644
22645  *       expect(counter.getText()).toContain('0');
22646  *       expect(debug.getText()).toContain('true');
22647  *     });
22648  *   </file>
22649  * </example>
22650  */
22651 var ngChangeDirective = valueFn({
22652   restrict: 'A',
22653   require: 'ngModel',
22654   link: function(scope, element, attr, ctrl) {
22655     ctrl.$viewChangeListeners.push(function() {
22656       scope.$eval(attr.ngChange);
22657     });
22658   }
22659 });
22660
22661 function classDirective(name, selector) {
22662   name = 'ngClass' + name;
22663   return ['$animate', function($animate) {
22664     return {
22665       restrict: 'AC',
22666       link: function(scope, element, attr) {
22667         var oldVal;
22668
22669         scope.$watch(attr[name], ngClassWatchAction, true);
22670
22671         attr.$observe('class', function(value) {
22672           ngClassWatchAction(scope.$eval(attr[name]));
22673         });
22674
22675
22676         if (name !== 'ngClass') {
22677           scope.$watch('$index', function($index, old$index) {
22678             // jshint bitwise: false
22679             var mod = $index & 1;
22680             if (mod !== (old$index & 1)) {
22681               var classes = arrayClasses(scope.$eval(attr[name]));
22682               mod === selector ?
22683                 addClasses(classes) :
22684                 removeClasses(classes);
22685             }
22686           });
22687         }
22688
22689         function addClasses(classes) {
22690           var newClasses = digestClassCounts(classes, 1);
22691           attr.$addClass(newClasses);
22692         }
22693
22694         function removeClasses(classes) {
22695           var newClasses = digestClassCounts(classes, -1);
22696           attr.$removeClass(newClasses);
22697         }
22698
22699         function digestClassCounts(classes, count) {
22700           // Use createMap() to prevent class assumptions involving property
22701           // names in Object.prototype
22702           var classCounts = element.data('$classCounts') || createMap();
22703           var classesToUpdate = [];
22704           forEach(classes, function(className) {
22705             if (count > 0 || classCounts[className]) {
22706               classCounts[className] = (classCounts[className] || 0) + count;
22707               if (classCounts[className] === +(count > 0)) {
22708                 classesToUpdate.push(className);
22709               }
22710             }
22711           });
22712           element.data('$classCounts', classCounts);
22713           return classesToUpdate.join(' ');
22714         }
22715
22716         function updateClasses(oldClasses, newClasses) {
22717           var toAdd = arrayDifference(newClasses, oldClasses);
22718           var toRemove = arrayDifference(oldClasses, newClasses);
22719           toAdd = digestClassCounts(toAdd, 1);
22720           toRemove = digestClassCounts(toRemove, -1);
22721           if (toAdd && toAdd.length) {
22722             $animate.addClass(element, toAdd);
22723           }
22724           if (toRemove && toRemove.length) {
22725             $animate.removeClass(element, toRemove);
22726           }
22727         }
22728
22729         function ngClassWatchAction(newVal) {
22730           if (selector === true || scope.$index % 2 === selector) {
22731             var newClasses = arrayClasses(newVal || []);
22732             if (!oldVal) {
22733               addClasses(newClasses);
22734             } else if (!equals(newVal,oldVal)) {
22735               var oldClasses = arrayClasses(oldVal);
22736               updateClasses(oldClasses, newClasses);
22737             }
22738           }
22739           oldVal = shallowCopy(newVal);
22740         }
22741       }
22742     };
22743
22744     function arrayDifference(tokens1, tokens2) {
22745       var values = [];
22746
22747       outer:
22748       for (var i = 0; i < tokens1.length; i++) {
22749         var token = tokens1[i];
22750         for (var j = 0; j < tokens2.length; j++) {
22751           if (token == tokens2[j]) continue outer;
22752         }
22753         values.push(token);
22754       }
22755       return values;
22756     }
22757
22758     function arrayClasses(classVal) {
22759       var classes = [];
22760       if (isArray(classVal)) {
22761         forEach(classVal, function(v) {
22762           classes = classes.concat(arrayClasses(v));
22763         });
22764         return classes;
22765       } else if (isString(classVal)) {
22766         return classVal.split(' ');
22767       } else if (isObject(classVal)) {
22768         forEach(classVal, function(v, k) {
22769           if (v) {
22770             classes = classes.concat(k.split(' '));
22771           }
22772         });
22773         return classes;
22774       }
22775       return classVal;
22776     }
22777   }];
22778 }
22779
22780 /**
22781  * @ngdoc directive
22782  * @name ngClass
22783  * @restrict AC
22784  *
22785  * @description
22786  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
22787  * an expression that represents all classes to be added.
22788  *
22789  * The directive operates in three different ways, depending on which of three types the expression
22790  * evaluates to:
22791  *
22792  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
22793  * names.
22794  *
22795  * 2. If the expression evaluates to an object, then for each key-value pair of the
22796  * object with a truthy value the corresponding key is used as a class name.
22797  *
22798  * 3. If the expression evaluates to an array, each element of the array should either be a string as in
22799  * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
22800  * to give you more control over what CSS classes appear. See the code below for an example of this.
22801  *
22802  *
22803  * The directive won't add duplicate classes if a particular class was already set.
22804  *
22805  * When the expression changes, the previously added classes are removed and only then are the
22806  * new classes added.
22807  *
22808  * @animations
22809  * **add** - happens just before the class is applied to the elements
22810  *
22811  * **remove** - happens just before the class is removed from the element
22812  *
22813  * @element ANY
22814  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
22815  *   of the evaluation can be a string representing space delimited class
22816  *   names, an array, or a map of class names to boolean values. In the case of a map, the
22817  *   names of the properties whose values are truthy will be added as css classes to the
22818  *   element.
22819  *
22820  * @example Example that demonstrates basic bindings via ngClass directive.
22821    <example>
22822      <file name="index.html">
22823        <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
22824        <label>
22825           <input type="checkbox" ng-model="deleted">
22826           deleted (apply "strike" class)
22827        </label><br>
22828        <label>
22829           <input type="checkbox" ng-model="important">
22830           important (apply "bold" class)
22831        </label><br>
22832        <label>
22833           <input type="checkbox" ng-model="error">
22834           error (apply "has-error" class)
22835        </label>
22836        <hr>
22837        <p ng-class="style">Using String Syntax</p>
22838        <input type="text" ng-model="style"
22839               placeholder="Type: bold strike red" aria-label="Type: bold strike red">
22840        <hr>
22841        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
22842        <input ng-model="style1"
22843               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
22844        <input ng-model="style2"
22845               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
22846        <input ng-model="style3"
22847               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
22848        <hr>
22849        <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
22850        <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
22851        <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
22852      </file>
22853      <file name="style.css">
22854        .strike {
22855            text-decoration: line-through;
22856        }
22857        .bold {
22858            font-weight: bold;
22859        }
22860        .red {
22861            color: red;
22862        }
22863        .has-error {
22864            color: red;
22865            background-color: yellow;
22866        }
22867        .orange {
22868            color: orange;
22869        }
22870      </file>
22871      <file name="protractor.js" type="protractor">
22872        var ps = element.all(by.css('p'));
22873
22874        it('should let you toggle the class', function() {
22875
22876          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
22877          expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
22878
22879          element(by.model('important')).click();
22880          expect(ps.first().getAttribute('class')).toMatch(/bold/);
22881
22882          element(by.model('error')).click();
22883          expect(ps.first().getAttribute('class')).toMatch(/has-error/);
22884        });
22885
22886        it('should let you toggle string example', function() {
22887          expect(ps.get(1).getAttribute('class')).toBe('');
22888          element(by.model('style')).clear();
22889          element(by.model('style')).sendKeys('red');
22890          expect(ps.get(1).getAttribute('class')).toBe('red');
22891        });
22892
22893        it('array example should have 3 classes', function() {
22894          expect(ps.get(2).getAttribute('class')).toBe('');
22895          element(by.model('style1')).sendKeys('bold');
22896          element(by.model('style2')).sendKeys('strike');
22897          element(by.model('style3')).sendKeys('red');
22898          expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
22899        });
22900
22901        it('array with map example should have 2 classes', function() {
22902          expect(ps.last().getAttribute('class')).toBe('');
22903          element(by.model('style4')).sendKeys('bold');
22904          element(by.model('warning')).click();
22905          expect(ps.last().getAttribute('class')).toBe('bold orange');
22906        });
22907      </file>
22908    </example>
22909
22910    ## Animations
22911
22912    The example below demonstrates how to perform animations using ngClass.
22913
22914    <example module="ngAnimate" deps="angular-animate.js" animations="true">
22915      <file name="index.html">
22916       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
22917       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
22918       <br>
22919       <span class="base-class" ng-class="myVar">Sample Text</span>
22920      </file>
22921      <file name="style.css">
22922        .base-class {
22923          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22924        }
22925
22926        .base-class.my-class {
22927          color: red;
22928          font-size:3em;
22929        }
22930      </file>
22931      <file name="protractor.js" type="protractor">
22932        it('should check ng-class', function() {
22933          expect(element(by.css('.base-class')).getAttribute('class')).not.
22934            toMatch(/my-class/);
22935
22936          element(by.id('setbtn')).click();
22937
22938          expect(element(by.css('.base-class')).getAttribute('class')).
22939            toMatch(/my-class/);
22940
22941          element(by.id('clearbtn')).click();
22942
22943          expect(element(by.css('.base-class')).getAttribute('class')).not.
22944            toMatch(/my-class/);
22945        });
22946      </file>
22947    </example>
22948
22949
22950    ## ngClass and pre-existing CSS3 Transitions/Animations
22951    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
22952    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
22953    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
22954    to view the step by step details of {@link $animate#addClass $animate.addClass} and
22955    {@link $animate#removeClass $animate.removeClass}.
22956  */
22957 var ngClassDirective = classDirective('', true);
22958
22959 /**
22960  * @ngdoc directive
22961  * @name ngClassOdd
22962  * @restrict AC
22963  *
22964  * @description
22965  * The `ngClassOdd` and `ngClassEven` directives work exactly as
22966  * {@link ng.directive:ngClass ngClass}, except they work in
22967  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
22968  *
22969  * This directive can be applied only within the scope of an
22970  * {@link ng.directive:ngRepeat ngRepeat}.
22971  *
22972  * @element ANY
22973  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
22974  *   of the evaluation can be a string representing space delimited class names or an array.
22975  *
22976  * @example
22977    <example>
22978      <file name="index.html">
22979         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
22980           <li ng-repeat="name in names">
22981            <span ng-class-odd="'odd'" ng-class-even="'even'">
22982              {{name}}
22983            </span>
22984           </li>
22985         </ol>
22986      </file>
22987      <file name="style.css">
22988        .odd {
22989          color: red;
22990        }
22991        .even {
22992          color: blue;
22993        }
22994      </file>
22995      <file name="protractor.js" type="protractor">
22996        it('should check ng-class-odd and ng-class-even', function() {
22997          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
22998            toMatch(/odd/);
22999          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23000            toMatch(/even/);
23001        });
23002      </file>
23003    </example>
23004  */
23005 var ngClassOddDirective = classDirective('Odd', 0);
23006
23007 /**
23008  * @ngdoc directive
23009  * @name ngClassEven
23010  * @restrict AC
23011  *
23012  * @description
23013  * The `ngClassOdd` and `ngClassEven` directives work exactly as
23014  * {@link ng.directive:ngClass ngClass}, except they work in
23015  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23016  *
23017  * This directive can be applied only within the scope of an
23018  * {@link ng.directive:ngRepeat ngRepeat}.
23019  *
23020  * @element ANY
23021  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
23022  *   result of the evaluation can be a string representing space delimited class names or an array.
23023  *
23024  * @example
23025    <example>
23026      <file name="index.html">
23027         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23028           <li ng-repeat="name in names">
23029            <span ng-class-odd="'odd'" ng-class-even="'even'">
23030              {{name}} &nbsp; &nbsp; &nbsp;
23031            </span>
23032           </li>
23033         </ol>
23034      </file>
23035      <file name="style.css">
23036        .odd {
23037          color: red;
23038        }
23039        .even {
23040          color: blue;
23041        }
23042      </file>
23043      <file name="protractor.js" type="protractor">
23044        it('should check ng-class-odd and ng-class-even', function() {
23045          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23046            toMatch(/odd/);
23047          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23048            toMatch(/even/);
23049        });
23050      </file>
23051    </example>
23052  */
23053 var ngClassEvenDirective = classDirective('Even', 1);
23054
23055 /**
23056  * @ngdoc directive
23057  * @name ngCloak
23058  * @restrict AC
23059  *
23060  * @description
23061  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
23062  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
23063  * directive to avoid the undesirable flicker effect caused by the html template display.
23064  *
23065  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
23066  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
23067  * of the browser view.
23068  *
23069  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
23070  * `angular.min.js`.
23071  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
23072  *
23073  * ```css
23074  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
23075  *   display: none !important;
23076  * }
23077  * ```
23078  *
23079  * When this css rule is loaded by the browser, all html elements (including their children) that
23080  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
23081  * during the compilation of the template it deletes the `ngCloak` element attribute, making
23082  * the compiled element visible.
23083  *
23084  * For the best result, the `angular.js` script must be loaded in the head section of the html
23085  * document; alternatively, the css rule above must be included in the external stylesheet of the
23086  * application.
23087  *
23088  * @element ANY
23089  *
23090  * @example
23091    <example>
23092      <file name="index.html">
23093         <div id="template1" ng-cloak>{{ 'hello' }}</div>
23094         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
23095      </file>
23096      <file name="protractor.js" type="protractor">
23097        it('should remove the template directive and css class', function() {
23098          expect($('#template1').getAttribute('ng-cloak')).
23099            toBeNull();
23100          expect($('#template2').getAttribute('ng-cloak')).
23101            toBeNull();
23102        });
23103      </file>
23104    </example>
23105  *
23106  */
23107 var ngCloakDirective = ngDirective({
23108   compile: function(element, attr) {
23109     attr.$set('ngCloak', undefined);
23110     element.removeClass('ng-cloak');
23111   }
23112 });
23113
23114 /**
23115  * @ngdoc directive
23116  * @name ngController
23117  *
23118  * @description
23119  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
23120  * supports the principles behind the Model-View-Controller design pattern.
23121  *
23122  * MVC components in angular:
23123  *
23124  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
23125  *   are accessed through bindings.
23126  * * View — The template (HTML with data bindings) that is rendered into the View.
23127  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
23128  *   logic behind the application to decorate the scope with functions and values
23129  *
23130  * Note that you can also attach controllers to the DOM by declaring it in a route definition
23131  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
23132  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
23133  * and executed twice.
23134  *
23135  * @element ANY
23136  * @scope
23137  * @priority 500
23138  * @param {expression} ngController Name of a constructor function registered with the current
23139  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
23140  * that on the current scope evaluates to a constructor function.
23141  *
23142  * The controller instance can be published into a scope property by specifying
23143  * `ng-controller="as propertyName"`.
23144  *
23145  * If the current `$controllerProvider` is configured to use globals (via
23146  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
23147  * also be the name of a globally accessible constructor function (not recommended).
23148  *
23149  * @example
23150  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
23151  * greeting are methods declared on the controller (see source tab). These methods can
23152  * easily be called from the angular markup. Any changes to the data are automatically reflected
23153  * in the View without the need for a manual update.
23154  *
23155  * Two different declaration styles are included below:
23156  *
23157  * * one binds methods and properties directly onto the controller using `this`:
23158  * `ng-controller="SettingsController1 as settings"`
23159  * * one injects `$scope` into the controller:
23160  * `ng-controller="SettingsController2"`
23161  *
23162  * The second option is more common in the Angular community, and is generally used in boilerplates
23163  * and in this guide. However, there are advantages to binding properties directly to the controller
23164  * and avoiding scope.
23165  *
23166  * * Using `controller as` makes it obvious which controller you are accessing in the template when
23167  * multiple controllers apply to an element.
23168  * * If you are writing your controllers as classes you have easier access to the properties and
23169  * methods, which will appear on the scope, from inside the controller code.
23170  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
23171  * inheritance masking primitives.
23172  *
23173  * This example demonstrates the `controller as` syntax.
23174  *
23175  * <example name="ngControllerAs" module="controllerAsExample">
23176  *   <file name="index.html">
23177  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
23178  *      <label>Name: <input type="text" ng-model="settings.name"/></label>
23179  *      <button ng-click="settings.greet()">greet</button><br/>
23180  *      Contact:
23181  *      <ul>
23182  *        <li ng-repeat="contact in settings.contacts">
23183  *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
23184  *             <option>phone</option>
23185  *             <option>email</option>
23186  *          </select>
23187  *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23188  *          <button ng-click="settings.clearContact(contact)">clear</button>
23189  *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
23190  *        </li>
23191  *        <li><button ng-click="settings.addContact()">add</button></li>
23192  *     </ul>
23193  *    </div>
23194  *   </file>
23195  *   <file name="app.js">
23196  *    angular.module('controllerAsExample', [])
23197  *      .controller('SettingsController1', SettingsController1);
23198  *
23199  *    function SettingsController1() {
23200  *      this.name = "John Smith";
23201  *      this.contacts = [
23202  *        {type: 'phone', value: '408 555 1212'},
23203  *        {type: 'email', value: 'john.smith@example.org'} ];
23204  *    }
23205  *
23206  *    SettingsController1.prototype.greet = function() {
23207  *      alert(this.name);
23208  *    };
23209  *
23210  *    SettingsController1.prototype.addContact = function() {
23211  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
23212  *    };
23213  *
23214  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
23215  *     var index = this.contacts.indexOf(contactToRemove);
23216  *      this.contacts.splice(index, 1);
23217  *    };
23218  *
23219  *    SettingsController1.prototype.clearContact = function(contact) {
23220  *      contact.type = 'phone';
23221  *      contact.value = '';
23222  *    };
23223  *   </file>
23224  *   <file name="protractor.js" type="protractor">
23225  *     it('should check controller as', function() {
23226  *       var container = element(by.id('ctrl-as-exmpl'));
23227  *         expect(container.element(by.model('settings.name'))
23228  *           .getAttribute('value')).toBe('John Smith');
23229  *
23230  *       var firstRepeat =
23231  *           container.element(by.repeater('contact in settings.contacts').row(0));
23232  *       var secondRepeat =
23233  *           container.element(by.repeater('contact in settings.contacts').row(1));
23234  *
23235  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23236  *           .toBe('408 555 1212');
23237  *
23238  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23239  *           .toBe('john.smith@example.org');
23240  *
23241  *       firstRepeat.element(by.buttonText('clear')).click();
23242  *
23243  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23244  *           .toBe('');
23245  *
23246  *       container.element(by.buttonText('add')).click();
23247  *
23248  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
23249  *           .element(by.model('contact.value'))
23250  *           .getAttribute('value'))
23251  *           .toBe('yourname@example.org');
23252  *     });
23253  *   </file>
23254  * </example>
23255  *
23256  * This example demonstrates the "attach to `$scope`" style of controller.
23257  *
23258  * <example name="ngController" module="controllerExample">
23259  *  <file name="index.html">
23260  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
23261  *     <label>Name: <input type="text" ng-model="name"/></label>
23262  *     <button ng-click="greet()">greet</button><br/>
23263  *     Contact:
23264  *     <ul>
23265  *       <li ng-repeat="contact in contacts">
23266  *         <select ng-model="contact.type" id="select_{{$index}}">
23267  *            <option>phone</option>
23268  *            <option>email</option>
23269  *         </select>
23270  *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23271  *         <button ng-click="clearContact(contact)">clear</button>
23272  *         <button ng-click="removeContact(contact)">X</button>
23273  *       </li>
23274  *       <li>[ <button ng-click="addContact()">add</button> ]</li>
23275  *    </ul>
23276  *   </div>
23277  *  </file>
23278  *  <file name="app.js">
23279  *   angular.module('controllerExample', [])
23280  *     .controller('SettingsController2', ['$scope', SettingsController2]);
23281  *
23282  *   function SettingsController2($scope) {
23283  *     $scope.name = "John Smith";
23284  *     $scope.contacts = [
23285  *       {type:'phone', value:'408 555 1212'},
23286  *       {type:'email', value:'john.smith@example.org'} ];
23287  *
23288  *     $scope.greet = function() {
23289  *       alert($scope.name);
23290  *     };
23291  *
23292  *     $scope.addContact = function() {
23293  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
23294  *     };
23295  *
23296  *     $scope.removeContact = function(contactToRemove) {
23297  *       var index = $scope.contacts.indexOf(contactToRemove);
23298  *       $scope.contacts.splice(index, 1);
23299  *     };
23300  *
23301  *     $scope.clearContact = function(contact) {
23302  *       contact.type = 'phone';
23303  *       contact.value = '';
23304  *     };
23305  *   }
23306  *  </file>
23307  *  <file name="protractor.js" type="protractor">
23308  *    it('should check controller', function() {
23309  *      var container = element(by.id('ctrl-exmpl'));
23310  *
23311  *      expect(container.element(by.model('name'))
23312  *          .getAttribute('value')).toBe('John Smith');
23313  *
23314  *      var firstRepeat =
23315  *          container.element(by.repeater('contact in contacts').row(0));
23316  *      var secondRepeat =
23317  *          container.element(by.repeater('contact in contacts').row(1));
23318  *
23319  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23320  *          .toBe('408 555 1212');
23321  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23322  *          .toBe('john.smith@example.org');
23323  *
23324  *      firstRepeat.element(by.buttonText('clear')).click();
23325  *
23326  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23327  *          .toBe('');
23328  *
23329  *      container.element(by.buttonText('add')).click();
23330  *
23331  *      expect(container.element(by.repeater('contact in contacts').row(2))
23332  *          .element(by.model('contact.value'))
23333  *          .getAttribute('value'))
23334  *          .toBe('yourname@example.org');
23335  *    });
23336  *  </file>
23337  *</example>
23338
23339  */
23340 var ngControllerDirective = [function() {
23341   return {
23342     restrict: 'A',
23343     scope: true,
23344     controller: '@',
23345     priority: 500
23346   };
23347 }];
23348
23349 /**
23350  * @ngdoc directive
23351  * @name ngCsp
23352  *
23353  * @element html
23354  * @description
23355  *
23356  * Angular has some features that can break certain
23357  * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
23358  *
23359  * If you intend to implement these rules then you must tell Angular not to use these features.
23360  *
23361  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
23362  *
23363  *
23364  * The following rules affect Angular:
23365  *
23366  * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
23367  * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
23368  * increase in the speed of evaluating Angular expressions.
23369  *
23370  * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
23371  * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
23372  * To make these directives work when a CSP rule is blocking inline styles, you must link to the
23373  * `angular-csp.css` in your HTML manually.
23374  *
23375  * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
23376  * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
23377  * however, triggers a CSP error to be logged in the console:
23378  *
23379  * ```
23380  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
23381  * script in the following Content Security Policy directive: "default-src 'self'". Note that
23382  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
23383  * ```
23384  *
23385  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
23386  * directive on an element of the HTML document that appears before the `<script>` tag that loads
23387  * the `angular.js` file.
23388  *
23389  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
23390  *
23391  * You can specify which of the CSP related Angular features should be deactivated by providing
23392  * a value for the `ng-csp` attribute. The options are as follows:
23393  *
23394  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
23395  *
23396  * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
23397  *
23398  * You can use these values in the following combinations:
23399  *
23400  *
23401  * * No declaration means that Angular will assume that you can do inline styles, but it will do
23402  * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
23403  * of Angular.
23404  *
23405  * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
23406  * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
23407  * of Angular.
23408  *
23409  * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
23410  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
23411  *
23412  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
23413  * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
23414  *
23415  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
23416  * styles nor use eval, which is the same as an empty: ng-csp.
23417  * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
23418  *
23419  * @example
23420  * This example shows how to apply the `ngCsp` directive to the `html` tag.
23421    ```html
23422      <!doctype html>
23423      <html ng-app ng-csp>
23424      ...
23425      ...
23426      </html>
23427    ```
23428   * @example
23429       // Note: the suffix `.csp` in the example name triggers
23430       // csp mode in our http server!
23431       <example name="example.csp" module="cspExample" ng-csp="true">
23432         <file name="index.html">
23433           <div ng-controller="MainController as ctrl">
23434             <div>
23435               <button ng-click="ctrl.inc()" id="inc">Increment</button>
23436               <span id="counter">
23437                 {{ctrl.counter}}
23438               </span>
23439             </div>
23440
23441             <div>
23442               <button ng-click="ctrl.evil()" id="evil">Evil</button>
23443               <span id="evilError">
23444                 {{ctrl.evilError}}
23445               </span>
23446             </div>
23447           </div>
23448         </file>
23449         <file name="script.js">
23450            angular.module('cspExample', [])
23451              .controller('MainController', function() {
23452                 this.counter = 0;
23453                 this.inc = function() {
23454                   this.counter++;
23455                 };
23456                 this.evil = function() {
23457                   // jshint evil:true
23458                   try {
23459                     eval('1+2');
23460                   } catch (e) {
23461                     this.evilError = e.message;
23462                   }
23463                 };
23464               });
23465         </file>
23466         <file name="protractor.js" type="protractor">
23467           var util, webdriver;
23468
23469           var incBtn = element(by.id('inc'));
23470           var counter = element(by.id('counter'));
23471           var evilBtn = element(by.id('evil'));
23472           var evilError = element(by.id('evilError'));
23473
23474           function getAndClearSevereErrors() {
23475             return browser.manage().logs().get('browser').then(function(browserLog) {
23476               return browserLog.filter(function(logEntry) {
23477                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
23478               });
23479             });
23480           }
23481
23482           function clearErrors() {
23483             getAndClearSevereErrors();
23484           }
23485
23486           function expectNoErrors() {
23487             getAndClearSevereErrors().then(function(filteredLog) {
23488               expect(filteredLog.length).toEqual(0);
23489               if (filteredLog.length) {
23490                 console.log('browser console errors: ' + util.inspect(filteredLog));
23491               }
23492             });
23493           }
23494
23495           function expectError(regex) {
23496             getAndClearSevereErrors().then(function(filteredLog) {
23497               var found = false;
23498               filteredLog.forEach(function(log) {
23499                 if (log.message.match(regex)) {
23500                   found = true;
23501                 }
23502               });
23503               if (!found) {
23504                 throw new Error('expected an error that matches ' + regex);
23505               }
23506             });
23507           }
23508
23509           beforeEach(function() {
23510             util = require('util');
23511             webdriver = require('protractor/node_modules/selenium-webdriver');
23512           });
23513
23514           // For now, we only test on Chrome,
23515           // as Safari does not load the page with Protractor's injected scripts,
23516           // and Firefox webdriver always disables content security policy (#6358)
23517           if (browser.params.browser !== 'chrome') {
23518             return;
23519           }
23520
23521           it('should not report errors when the page is loaded', function() {
23522             // clear errors so we are not dependent on previous tests
23523             clearErrors();
23524             // Need to reload the page as the page is already loaded when
23525             // we come here
23526             browser.driver.getCurrentUrl().then(function(url) {
23527               browser.get(url);
23528             });
23529             expectNoErrors();
23530           });
23531
23532           it('should evaluate expressions', function() {
23533             expect(counter.getText()).toEqual('0');
23534             incBtn.click();
23535             expect(counter.getText()).toEqual('1');
23536             expectNoErrors();
23537           });
23538
23539           it('should throw and report an error when using "eval"', function() {
23540             evilBtn.click();
23541             expect(evilError.getText()).toMatch(/Content Security Policy/);
23542             expectError(/Content Security Policy/);
23543           });
23544         </file>
23545       </example>
23546   */
23547
23548 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
23549 // bootstrap the system (before $parse is instantiated), for this reason we just have
23550 // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
23551
23552 /**
23553  * @ngdoc directive
23554  * @name ngClick
23555  *
23556  * @description
23557  * The ngClick directive allows you to specify custom behavior when
23558  * an element is clicked.
23559  *
23560  * @element ANY
23561  * @priority 0
23562  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
23563  * click. ({@link guide/expression#-event- Event object is available as `$event`})
23564  *
23565  * @example
23566    <example>
23567      <file name="index.html">
23568       <button ng-click="count = count + 1" ng-init="count=0">
23569         Increment
23570       </button>
23571       <span>
23572         count: {{count}}
23573       </span>
23574      </file>
23575      <file name="protractor.js" type="protractor">
23576        it('should check ng-click', function() {
23577          expect(element(by.binding('count')).getText()).toMatch('0');
23578          element(by.css('button')).click();
23579          expect(element(by.binding('count')).getText()).toMatch('1');
23580        });
23581      </file>
23582    </example>
23583  */
23584 /*
23585  * A collection of directives that allows creation of custom event handlers that are defined as
23586  * angular expressions and are compiled and executed within the current scope.
23587  */
23588 var ngEventDirectives = {};
23589
23590 // For events that might fire synchronously during DOM manipulation
23591 // we need to execute their event handlers asynchronously using $evalAsync,
23592 // so that they are not executed in an inconsistent state.
23593 var forceAsyncEvents = {
23594   'blur': true,
23595   'focus': true
23596 };
23597 forEach(
23598   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
23599   function(eventName) {
23600     var directiveName = directiveNormalize('ng-' + eventName);
23601     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
23602       return {
23603         restrict: 'A',
23604         compile: function($element, attr) {
23605           // We expose the powerful $event object on the scope that provides access to the Window,
23606           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
23607           // checks at the cost of speed since event handler expressions are not executed as
23608           // frequently as regular change detection.
23609           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
23610           return function ngEventHandler(scope, element) {
23611             element.on(eventName, function(event) {
23612               var callback = function() {
23613                 fn(scope, {$event:event});
23614               };
23615               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
23616                 scope.$evalAsync(callback);
23617               } else {
23618                 scope.$apply(callback);
23619               }
23620             });
23621           };
23622         }
23623       };
23624     }];
23625   }
23626 );
23627
23628 /**
23629  * @ngdoc directive
23630  * @name ngDblclick
23631  *
23632  * @description
23633  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
23634  *
23635  * @element ANY
23636  * @priority 0
23637  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
23638  * a dblclick. (The Event object is available as `$event`)
23639  *
23640  * @example
23641    <example>
23642      <file name="index.html">
23643       <button ng-dblclick="count = count + 1" ng-init="count=0">
23644         Increment (on double click)
23645       </button>
23646       count: {{count}}
23647      </file>
23648    </example>
23649  */
23650
23651
23652 /**
23653  * @ngdoc directive
23654  * @name ngMousedown
23655  *
23656  * @description
23657  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
23658  *
23659  * @element ANY
23660  * @priority 0
23661  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
23662  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
23663  *
23664  * @example
23665    <example>
23666      <file name="index.html">
23667       <button ng-mousedown="count = count + 1" ng-init="count=0">
23668         Increment (on mouse down)
23669       </button>
23670       count: {{count}}
23671      </file>
23672    </example>
23673  */
23674
23675
23676 /**
23677  * @ngdoc directive
23678  * @name ngMouseup
23679  *
23680  * @description
23681  * Specify custom behavior on mouseup event.
23682  *
23683  * @element ANY
23684  * @priority 0
23685  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
23686  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
23687  *
23688  * @example
23689    <example>
23690      <file name="index.html">
23691       <button ng-mouseup="count = count + 1" ng-init="count=0">
23692         Increment (on mouse up)
23693       </button>
23694       count: {{count}}
23695      </file>
23696    </example>
23697  */
23698
23699 /**
23700  * @ngdoc directive
23701  * @name ngMouseover
23702  *
23703  * @description
23704  * Specify custom behavior on mouseover event.
23705  *
23706  * @element ANY
23707  * @priority 0
23708  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
23709  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
23710  *
23711  * @example
23712    <example>
23713      <file name="index.html">
23714       <button ng-mouseover="count = count + 1" ng-init="count=0">
23715         Increment (when mouse is over)
23716       </button>
23717       count: {{count}}
23718      </file>
23719    </example>
23720  */
23721
23722
23723 /**
23724  * @ngdoc directive
23725  * @name ngMouseenter
23726  *
23727  * @description
23728  * Specify custom behavior on mouseenter event.
23729  *
23730  * @element ANY
23731  * @priority 0
23732  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
23733  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
23734  *
23735  * @example
23736    <example>
23737      <file name="index.html">
23738       <button ng-mouseenter="count = count + 1" ng-init="count=0">
23739         Increment (when mouse enters)
23740       </button>
23741       count: {{count}}
23742      </file>
23743    </example>
23744  */
23745
23746
23747 /**
23748  * @ngdoc directive
23749  * @name ngMouseleave
23750  *
23751  * @description
23752  * Specify custom behavior on mouseleave event.
23753  *
23754  * @element ANY
23755  * @priority 0
23756  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
23757  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
23758  *
23759  * @example
23760    <example>
23761      <file name="index.html">
23762       <button ng-mouseleave="count = count + 1" ng-init="count=0">
23763         Increment (when mouse leaves)
23764       </button>
23765       count: {{count}}
23766      </file>
23767    </example>
23768  */
23769
23770
23771 /**
23772  * @ngdoc directive
23773  * @name ngMousemove
23774  *
23775  * @description
23776  * Specify custom behavior on mousemove event.
23777  *
23778  * @element ANY
23779  * @priority 0
23780  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
23781  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
23782  *
23783  * @example
23784    <example>
23785      <file name="index.html">
23786       <button ng-mousemove="count = count + 1" ng-init="count=0">
23787         Increment (when mouse moves)
23788       </button>
23789       count: {{count}}
23790      </file>
23791    </example>
23792  */
23793
23794
23795 /**
23796  * @ngdoc directive
23797  * @name ngKeydown
23798  *
23799  * @description
23800  * Specify custom behavior on keydown event.
23801  *
23802  * @element ANY
23803  * @priority 0
23804  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
23805  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23806  *
23807  * @example
23808    <example>
23809      <file name="index.html">
23810       <input ng-keydown="count = count + 1" ng-init="count=0">
23811       key down count: {{count}}
23812      </file>
23813    </example>
23814  */
23815
23816
23817 /**
23818  * @ngdoc directive
23819  * @name ngKeyup
23820  *
23821  * @description
23822  * Specify custom behavior on keyup event.
23823  *
23824  * @element ANY
23825  * @priority 0
23826  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
23827  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23828  *
23829  * @example
23830    <example>
23831      <file name="index.html">
23832        <p>Typing in the input box below updates the key count</p>
23833        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
23834
23835        <p>Typing in the input box below updates the keycode</p>
23836        <input ng-keyup="event=$event">
23837        <p>event keyCode: {{ event.keyCode }}</p>
23838        <p>event altKey: {{ event.altKey }}</p>
23839      </file>
23840    </example>
23841  */
23842
23843
23844 /**
23845  * @ngdoc directive
23846  * @name ngKeypress
23847  *
23848  * @description
23849  * Specify custom behavior on keypress event.
23850  *
23851  * @element ANY
23852  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
23853  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
23854  * and can be interrogated for keyCode, altKey, etc.)
23855  *
23856  * @example
23857    <example>
23858      <file name="index.html">
23859       <input ng-keypress="count = count + 1" ng-init="count=0">
23860       key press count: {{count}}
23861      </file>
23862    </example>
23863  */
23864
23865
23866 /**
23867  * @ngdoc directive
23868  * @name ngSubmit
23869  *
23870  * @description
23871  * Enables binding angular expressions to onsubmit events.
23872  *
23873  * Additionally it prevents the default action (which for form means sending the request to the
23874  * server and reloading the current page), but only if the form does not contain `action`,
23875  * `data-action`, or `x-action` attributes.
23876  *
23877  * <div class="alert alert-warning">
23878  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
23879  * `ngSubmit` handlers together. See the
23880  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
23881  * for a detailed discussion of when `ngSubmit` may be triggered.
23882  * </div>
23883  *
23884  * @element form
23885  * @priority 0
23886  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
23887  * ({@link guide/expression#-event- Event object is available as `$event`})
23888  *
23889  * @example
23890    <example module="submitExample">
23891      <file name="index.html">
23892       <script>
23893         angular.module('submitExample', [])
23894           .controller('ExampleController', ['$scope', function($scope) {
23895             $scope.list = [];
23896             $scope.text = 'hello';
23897             $scope.submit = function() {
23898               if ($scope.text) {
23899                 $scope.list.push(this.text);
23900                 $scope.text = '';
23901               }
23902             };
23903           }]);
23904       </script>
23905       <form ng-submit="submit()" ng-controller="ExampleController">
23906         Enter text and hit enter:
23907         <input type="text" ng-model="text" name="text" />
23908         <input type="submit" id="submit" value="Submit" />
23909         <pre>list={{list}}</pre>
23910       </form>
23911      </file>
23912      <file name="protractor.js" type="protractor">
23913        it('should check ng-submit', function() {
23914          expect(element(by.binding('list')).getText()).toBe('list=[]');
23915          element(by.css('#submit')).click();
23916          expect(element(by.binding('list')).getText()).toContain('hello');
23917          expect(element(by.model('text')).getAttribute('value')).toBe('');
23918        });
23919        it('should ignore empty strings', function() {
23920          expect(element(by.binding('list')).getText()).toBe('list=[]');
23921          element(by.css('#submit')).click();
23922          element(by.css('#submit')).click();
23923          expect(element(by.binding('list')).getText()).toContain('hello');
23924         });
23925      </file>
23926    </example>
23927  */
23928
23929 /**
23930  * @ngdoc directive
23931  * @name ngFocus
23932  *
23933  * @description
23934  * Specify custom behavior on focus event.
23935  *
23936  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
23937  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
23938  * during an `$apply` to ensure a consistent state.
23939  *
23940  * @element window, input, select, textarea, a
23941  * @priority 0
23942  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
23943  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
23944  *
23945  * @example
23946  * See {@link ng.directive:ngClick ngClick}
23947  */
23948
23949 /**
23950  * @ngdoc directive
23951  * @name ngBlur
23952  *
23953  * @description
23954  * Specify custom behavior on blur event.
23955  *
23956  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
23957  * an element has lost focus.
23958  *
23959  * Note: As the `blur` event is executed synchronously also during DOM manipulations
23960  * (e.g. removing a focussed input),
23961  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
23962  * during an `$apply` to ensure a consistent state.
23963  *
23964  * @element window, input, select, textarea, a
23965  * @priority 0
23966  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
23967  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
23968  *
23969  * @example
23970  * See {@link ng.directive:ngClick ngClick}
23971  */
23972
23973 /**
23974  * @ngdoc directive
23975  * @name ngCopy
23976  *
23977  * @description
23978  * Specify custom behavior on copy event.
23979  *
23980  * @element window, input, select, textarea, a
23981  * @priority 0
23982  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
23983  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
23984  *
23985  * @example
23986    <example>
23987      <file name="index.html">
23988       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
23989       copied: {{copied}}
23990      </file>
23991    </example>
23992  */
23993
23994 /**
23995  * @ngdoc directive
23996  * @name ngCut
23997  *
23998  * @description
23999  * Specify custom behavior on cut event.
24000  *
24001  * @element window, input, select, textarea, a
24002  * @priority 0
24003  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
24004  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
24005  *
24006  * @example
24007    <example>
24008      <file name="index.html">
24009       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
24010       cut: {{cut}}
24011      </file>
24012    </example>
24013  */
24014
24015 /**
24016  * @ngdoc directive
24017  * @name ngPaste
24018  *
24019  * @description
24020  * Specify custom behavior on paste event.
24021  *
24022  * @element window, input, select, textarea, a
24023  * @priority 0
24024  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
24025  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
24026  *
24027  * @example
24028    <example>
24029      <file name="index.html">
24030       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
24031       pasted: {{paste}}
24032      </file>
24033    </example>
24034  */
24035
24036 /**
24037  * @ngdoc directive
24038  * @name ngIf
24039  * @restrict A
24040  * @multiElement
24041  *
24042  * @description
24043  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
24044  * {expression}. If the expression assigned to `ngIf` evaluates to a false
24045  * value then the element is removed from the DOM, otherwise a clone of the
24046  * element is reinserted into the DOM.
24047  *
24048  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
24049  * element in the DOM rather than changing its visibility via the `display` css property.  A common
24050  * case when this difference is significant is when using css selectors that rely on an element's
24051  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
24052  *
24053  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
24054  * is created when the element is restored.  The scope created within `ngIf` inherits from
24055  * its parent scope using
24056  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
24057  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
24058  * a javascript primitive defined in the parent scope. In this case any modifications made to the
24059  * variable within the child scope will override (hide) the value in the parent scope.
24060  *
24061  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
24062  * is if an element's class attribute is directly modified after it's compiled, using something like
24063  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
24064  * the added class will be lost because the original compiled state is used to regenerate the element.
24065  *
24066  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
24067  * and `leave` effects.
24068  *
24069  * @animations
24070  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
24071  * leave - happens just before the `ngIf` contents are removed from the DOM
24072  *
24073  * @element ANY
24074  * @scope
24075  * @priority 600
24076  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
24077  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
24078  *     element is added to the DOM tree.
24079  *
24080  * @example
24081   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24082     <file name="index.html">
24083       <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
24084       Show when checked:
24085       <span ng-if="checked" class="animate-if">
24086         This is removed when the checkbox is unchecked.
24087       </span>
24088     </file>
24089     <file name="animations.css">
24090       .animate-if {
24091         background:white;
24092         border:1px solid black;
24093         padding:10px;
24094       }
24095
24096       .animate-if.ng-enter, .animate-if.ng-leave {
24097         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24098       }
24099
24100       .animate-if.ng-enter,
24101       .animate-if.ng-leave.ng-leave-active {
24102         opacity:0;
24103       }
24104
24105       .animate-if.ng-leave,
24106       .animate-if.ng-enter.ng-enter-active {
24107         opacity:1;
24108       }
24109     </file>
24110   </example>
24111  */
24112 var ngIfDirective = ['$animate', function($animate) {
24113   return {
24114     multiElement: true,
24115     transclude: 'element',
24116     priority: 600,
24117     terminal: true,
24118     restrict: 'A',
24119     $$tlb: true,
24120     link: function($scope, $element, $attr, ctrl, $transclude) {
24121         var block, childScope, previousElements;
24122         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
24123
24124           if (value) {
24125             if (!childScope) {
24126               $transclude(function(clone, newScope) {
24127                 childScope = newScope;
24128                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
24129                 // Note: We only need the first/last node of the cloned nodes.
24130                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24131                 // by a directive with templateUrl when its template arrives.
24132                 block = {
24133                   clone: clone
24134                 };
24135                 $animate.enter(clone, $element.parent(), $element);
24136               });
24137             }
24138           } else {
24139             if (previousElements) {
24140               previousElements.remove();
24141               previousElements = null;
24142             }
24143             if (childScope) {
24144               childScope.$destroy();
24145               childScope = null;
24146             }
24147             if (block) {
24148               previousElements = getBlockNodes(block.clone);
24149               $animate.leave(previousElements).then(function() {
24150                 previousElements = null;
24151               });
24152               block = null;
24153             }
24154           }
24155         });
24156     }
24157   };
24158 }];
24159
24160 /**
24161  * @ngdoc directive
24162  * @name ngInclude
24163  * @restrict ECA
24164  *
24165  * @description
24166  * Fetches, compiles and includes an external HTML fragment.
24167  *
24168  * By default, the template URL is restricted to the same domain and protocol as the
24169  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
24170  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
24171  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
24172  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
24173  * ng.$sce Strict Contextual Escaping}.
24174  *
24175  * In addition, the browser's
24176  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
24177  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
24178  * policy may further restrict whether the template is successfully loaded.
24179  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
24180  * access on some browsers.
24181  *
24182  * @animations
24183  * enter - animation is used to bring new content into the browser.
24184  * leave - animation is used to animate existing content away.
24185  *
24186  * The enter and leave animation occur concurrently.
24187  *
24188  * @scope
24189  * @priority 400
24190  *
24191  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24192  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24193  * @param {string=} onload Expression to evaluate when a new partial is loaded.
24194  *                  <div class="alert alert-warning">
24195  *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
24196  *                  a function with the name on the window element, which will usually throw a
24197  *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
24198  *                  different form that {@link guide/directive#normalization matches} `onload`.
24199  *                  </div>
24200    *
24201  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24202  *                  $anchorScroll} to scroll the viewport after the content is loaded.
24203  *
24204  *                  - If the attribute is not set, disable scrolling.
24205  *                  - If the attribute is set without value, enable scrolling.
24206  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
24207  *
24208  * @example
24209   <example module="includeExample" deps="angular-animate.js" animations="true">
24210     <file name="index.html">
24211      <div ng-controller="ExampleController">
24212        <select ng-model="template" ng-options="t.name for t in templates">
24213         <option value="">(blank)</option>
24214        </select>
24215        url of the template: <code>{{template.url}}</code>
24216        <hr/>
24217        <div class="slide-animate-container">
24218          <div class="slide-animate" ng-include="template.url"></div>
24219        </div>
24220      </div>
24221     </file>
24222     <file name="script.js">
24223       angular.module('includeExample', ['ngAnimate'])
24224         .controller('ExampleController', ['$scope', function($scope) {
24225           $scope.templates =
24226             [ { name: 'template1.html', url: 'template1.html'},
24227               { name: 'template2.html', url: 'template2.html'} ];
24228           $scope.template = $scope.templates[0];
24229         }]);
24230      </file>
24231     <file name="template1.html">
24232       Content of template1.html
24233     </file>
24234     <file name="template2.html">
24235       Content of template2.html
24236     </file>
24237     <file name="animations.css">
24238       .slide-animate-container {
24239         position:relative;
24240         background:white;
24241         border:1px solid black;
24242         height:40px;
24243         overflow:hidden;
24244       }
24245
24246       .slide-animate {
24247         padding:10px;
24248       }
24249
24250       .slide-animate.ng-enter, .slide-animate.ng-leave {
24251         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24252
24253         position:absolute;
24254         top:0;
24255         left:0;
24256         right:0;
24257         bottom:0;
24258         display:block;
24259         padding:10px;
24260       }
24261
24262       .slide-animate.ng-enter {
24263         top:-50px;
24264       }
24265       .slide-animate.ng-enter.ng-enter-active {
24266         top:0;
24267       }
24268
24269       .slide-animate.ng-leave {
24270         top:0;
24271       }
24272       .slide-animate.ng-leave.ng-leave-active {
24273         top:50px;
24274       }
24275     </file>
24276     <file name="protractor.js" type="protractor">
24277       var templateSelect = element(by.model('template'));
24278       var includeElem = element(by.css('[ng-include]'));
24279
24280       it('should load template1.html', function() {
24281         expect(includeElem.getText()).toMatch(/Content of template1.html/);
24282       });
24283
24284       it('should load template2.html', function() {
24285         if (browser.params.browser == 'firefox') {
24286           // Firefox can't handle using selects
24287           // See https://github.com/angular/protractor/issues/480
24288           return;
24289         }
24290         templateSelect.click();
24291         templateSelect.all(by.css('option')).get(2).click();
24292         expect(includeElem.getText()).toMatch(/Content of template2.html/);
24293       });
24294
24295       it('should change to blank', function() {
24296         if (browser.params.browser == 'firefox') {
24297           // Firefox can't handle using selects
24298           return;
24299         }
24300         templateSelect.click();
24301         templateSelect.all(by.css('option')).get(0).click();
24302         expect(includeElem.isPresent()).toBe(false);
24303       });
24304     </file>
24305   </example>
24306  */
24307
24308
24309 /**
24310  * @ngdoc event
24311  * @name ngInclude#$includeContentRequested
24312  * @eventType emit on the scope ngInclude was declared in
24313  * @description
24314  * Emitted every time the ngInclude content is requested.
24315  *
24316  * @param {Object} angularEvent Synthetic event object.
24317  * @param {String} src URL of content to load.
24318  */
24319
24320
24321 /**
24322  * @ngdoc event
24323  * @name ngInclude#$includeContentLoaded
24324  * @eventType emit on the current ngInclude scope
24325  * @description
24326  * Emitted every time the ngInclude content is reloaded.
24327  *
24328  * @param {Object} angularEvent Synthetic event object.
24329  * @param {String} src URL of content to load.
24330  */
24331
24332
24333 /**
24334  * @ngdoc event
24335  * @name ngInclude#$includeContentError
24336  * @eventType emit on the scope ngInclude was declared in
24337  * @description
24338  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
24339  *
24340  * @param {Object} angularEvent Synthetic event object.
24341  * @param {String} src URL of content to load.
24342  */
24343 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24344                   function($templateRequest,   $anchorScroll,   $animate) {
24345   return {
24346     restrict: 'ECA',
24347     priority: 400,
24348     terminal: true,
24349     transclude: 'element',
24350     controller: angular.noop,
24351     compile: function(element, attr) {
24352       var srcExp = attr.ngInclude || attr.src,
24353           onloadExp = attr.onload || '',
24354           autoScrollExp = attr.autoscroll;
24355
24356       return function(scope, $element, $attr, ctrl, $transclude) {
24357         var changeCounter = 0,
24358             currentScope,
24359             previousElement,
24360             currentElement;
24361
24362         var cleanupLastIncludeContent = function() {
24363           if (previousElement) {
24364             previousElement.remove();
24365             previousElement = null;
24366           }
24367           if (currentScope) {
24368             currentScope.$destroy();
24369             currentScope = null;
24370           }
24371           if (currentElement) {
24372             $animate.leave(currentElement).then(function() {
24373               previousElement = null;
24374             });
24375             previousElement = currentElement;
24376             currentElement = null;
24377           }
24378         };
24379
24380         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
24381           var afterAnimation = function() {
24382             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
24383               $anchorScroll();
24384             }
24385           };
24386           var thisChangeId = ++changeCounter;
24387
24388           if (src) {
24389             //set the 2nd param to true to ignore the template request error so that the inner
24390             //contents and scope can be cleaned up.
24391             $templateRequest(src, true).then(function(response) {
24392               if (thisChangeId !== changeCounter) return;
24393               var newScope = scope.$new();
24394               ctrl.template = response;
24395
24396               // Note: This will also link all children of ng-include that were contained in the original
24397               // html. If that content contains controllers, ... they could pollute/change the scope.
24398               // However, using ng-include on an element with additional content does not make sense...
24399               // Note: We can't remove them in the cloneAttchFn of $transclude as that
24400               // function is called before linking the content, which would apply child
24401               // directives to non existing elements.
24402               var clone = $transclude(newScope, function(clone) {
24403                 cleanupLastIncludeContent();
24404                 $animate.enter(clone, null, $element).then(afterAnimation);
24405               });
24406
24407               currentScope = newScope;
24408               currentElement = clone;
24409
24410               currentScope.$emit('$includeContentLoaded', src);
24411               scope.$eval(onloadExp);
24412             }, function() {
24413               if (thisChangeId === changeCounter) {
24414                 cleanupLastIncludeContent();
24415                 scope.$emit('$includeContentError', src);
24416               }
24417             });
24418             scope.$emit('$includeContentRequested', src);
24419           } else {
24420             cleanupLastIncludeContent();
24421             ctrl.template = null;
24422           }
24423         });
24424       };
24425     }
24426   };
24427 }];
24428
24429 // This directive is called during the $transclude call of the first `ngInclude` directive.
24430 // It will replace and compile the content of the element with the loaded template.
24431 // We need this directive so that the element content is already filled when
24432 // the link function of another directive on the same element as ngInclude
24433 // is called.
24434 var ngIncludeFillContentDirective = ['$compile',
24435   function($compile) {
24436     return {
24437       restrict: 'ECA',
24438       priority: -400,
24439       require: 'ngInclude',
24440       link: function(scope, $element, $attr, ctrl) {
24441         if (/SVG/.test($element[0].toString())) {
24442           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
24443           // support innerHTML, so detect this here and try to generate the contents
24444           // specially.
24445           $element.empty();
24446           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
24447               function namespaceAdaptedClone(clone) {
24448             $element.append(clone);
24449           }, {futureParentElement: $element});
24450           return;
24451         }
24452
24453         $element.html(ctrl.template);
24454         $compile($element.contents())(scope);
24455       }
24456     };
24457   }];
24458
24459 /**
24460  * @ngdoc directive
24461  * @name ngInit
24462  * @restrict AC
24463  *
24464  * @description
24465  * The `ngInit` directive allows you to evaluate an expression in the
24466  * current scope.
24467  *
24468  * <div class="alert alert-danger">
24469  * This directive can be abused to add unnecessary amounts of logic into your templates.
24470  * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
24471  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
24472  * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
24473  * rather than `ngInit` to initialize values on a scope.
24474  * </div>
24475  *
24476  * <div class="alert alert-warning">
24477  * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
24478  * sure you have parentheses to ensure correct operator precedence:
24479  * <pre class="prettyprint">
24480  * `<div ng-init="test1 = ($index | toString)"></div>`
24481  * </pre>
24482  * </div>
24483  *
24484  * @priority 450
24485  *
24486  * @element ANY
24487  * @param {expression} ngInit {@link guide/expression Expression} to eval.
24488  *
24489  * @example
24490    <example module="initExample">
24491      <file name="index.html">
24492    <script>
24493      angular.module('initExample', [])
24494        .controller('ExampleController', ['$scope', function($scope) {
24495          $scope.list = [['a', 'b'], ['c', 'd']];
24496        }]);
24497    </script>
24498    <div ng-controller="ExampleController">
24499      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
24500        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
24501           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
24502        </div>
24503      </div>
24504    </div>
24505      </file>
24506      <file name="protractor.js" type="protractor">
24507        it('should alias index positions', function() {
24508          var elements = element.all(by.css('.example-init'));
24509          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
24510          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
24511          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
24512          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
24513        });
24514      </file>
24515    </example>
24516  */
24517 var ngInitDirective = ngDirective({
24518   priority: 450,
24519   compile: function() {
24520     return {
24521       pre: function(scope, element, attrs) {
24522         scope.$eval(attrs.ngInit);
24523       }
24524     };
24525   }
24526 });
24527
24528 /**
24529  * @ngdoc directive
24530  * @name ngList
24531  *
24532  * @description
24533  * Text input that converts between a delimited string and an array of strings. The default
24534  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
24535  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
24536  *
24537  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
24538  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
24539  *   list item is respected. This implies that the user of the directive is responsible for
24540  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
24541  *   tab or newline character.
24542  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
24543  *   when joining the list items back together) and whitespace around each list item is stripped
24544  *   before it is added to the model.
24545  *
24546  * ### Example with Validation
24547  *
24548  * <example name="ngList-directive" module="listExample">
24549  *   <file name="app.js">
24550  *      angular.module('listExample', [])
24551  *        .controller('ExampleController', ['$scope', function($scope) {
24552  *          $scope.names = ['morpheus', 'neo', 'trinity'];
24553  *        }]);
24554  *   </file>
24555  *   <file name="index.html">
24556  *    <form name="myForm" ng-controller="ExampleController">
24557  *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
24558  *      <span role="alert">
24559  *        <span class="error" ng-show="myForm.namesInput.$error.required">
24560  *        Required!</span>
24561  *      </span>
24562  *      <br>
24563  *      <tt>names = {{names}}</tt><br/>
24564  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
24565  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
24566  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24567  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24568  *     </form>
24569  *   </file>
24570  *   <file name="protractor.js" type="protractor">
24571  *     var listInput = element(by.model('names'));
24572  *     var names = element(by.exactBinding('names'));
24573  *     var valid = element(by.binding('myForm.namesInput.$valid'));
24574  *     var error = element(by.css('span.error'));
24575  *
24576  *     it('should initialize to model', function() {
24577  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
24578  *       expect(valid.getText()).toContain('true');
24579  *       expect(error.getCssValue('display')).toBe('none');
24580  *     });
24581  *
24582  *     it('should be invalid if empty', function() {
24583  *       listInput.clear();
24584  *       listInput.sendKeys('');
24585  *
24586  *       expect(names.getText()).toContain('');
24587  *       expect(valid.getText()).toContain('false');
24588  *       expect(error.getCssValue('display')).not.toBe('none');
24589  *     });
24590  *   </file>
24591  * </example>
24592  *
24593  * ### Example - splitting on newline
24594  * <example name="ngList-directive-newlines">
24595  *   <file name="index.html">
24596  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
24597  *    <pre>{{ list | json }}</pre>
24598  *   </file>
24599  *   <file name="protractor.js" type="protractor">
24600  *     it("should split the text by newlines", function() {
24601  *       var listInput = element(by.model('list'));
24602  *       var output = element(by.binding('list | json'));
24603  *       listInput.sendKeys('abc\ndef\nghi');
24604  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
24605  *     });
24606  *   </file>
24607  * </example>
24608  *
24609  * @element input
24610  * @param {string=} ngList optional delimiter that should be used to split the value.
24611  */
24612 var ngListDirective = function() {
24613   return {
24614     restrict: 'A',
24615     priority: 100,
24616     require: 'ngModel',
24617     link: function(scope, element, attr, ctrl) {
24618       // We want to control whitespace trimming so we use this convoluted approach
24619       // to access the ngList attribute, which doesn't pre-trim the attribute
24620       var ngList = element.attr(attr.$attr.ngList) || ', ';
24621       var trimValues = attr.ngTrim !== 'false';
24622       var separator = trimValues ? trim(ngList) : ngList;
24623
24624       var parse = function(viewValue) {
24625         // If the viewValue is invalid (say required but empty) it will be `undefined`
24626         if (isUndefined(viewValue)) return;
24627
24628         var list = [];
24629
24630         if (viewValue) {
24631           forEach(viewValue.split(separator), function(value) {
24632             if (value) list.push(trimValues ? trim(value) : value);
24633           });
24634         }
24635
24636         return list;
24637       };
24638
24639       ctrl.$parsers.push(parse);
24640       ctrl.$formatters.push(function(value) {
24641         if (isArray(value)) {
24642           return value.join(ngList);
24643         }
24644
24645         return undefined;
24646       });
24647
24648       // Override the standard $isEmpty because an empty array means the input is empty.
24649       ctrl.$isEmpty = function(value) {
24650         return !value || !value.length;
24651       };
24652     }
24653   };
24654 };
24655
24656 /* global VALID_CLASS: true,
24657   INVALID_CLASS: true,
24658   PRISTINE_CLASS: true,
24659   DIRTY_CLASS: true,
24660   UNTOUCHED_CLASS: true,
24661   TOUCHED_CLASS: true,
24662 */
24663
24664 var VALID_CLASS = 'ng-valid',
24665     INVALID_CLASS = 'ng-invalid',
24666     PRISTINE_CLASS = 'ng-pristine',
24667     DIRTY_CLASS = 'ng-dirty',
24668     UNTOUCHED_CLASS = 'ng-untouched',
24669     TOUCHED_CLASS = 'ng-touched',
24670     PENDING_CLASS = 'ng-pending';
24671
24672 var ngModelMinErr = minErr('ngModel');
24673
24674 /**
24675  * @ngdoc type
24676  * @name ngModel.NgModelController
24677  *
24678  * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
24679  * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
24680  * is set.
24681  * @property {*} $modelValue The value in the model that the control is bound to.
24682  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
24683        the control reads value from the DOM. The functions are called in array order, each passing
24684        its return value through to the next. The last return value is forwarded to the
24685        {@link ngModel.NgModelController#$validators `$validators`} collection.
24686
24687 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
24688 `$viewValue`}.
24689
24690 Returning `undefined` from a parser means a parse error occurred. In that case,
24691 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
24692 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
24693 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
24694
24695  *
24696  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
24697        the model value changes. The functions are called in reverse array order, each passing the value through to the
24698        next. The last return value is used as the actual DOM value.
24699        Used to format / convert values for display in the control.
24700  * ```js
24701  * function formatter(value) {
24702  *   if (value) {
24703  *     return value.toUpperCase();
24704  *   }
24705  * }
24706  * ngModel.$formatters.push(formatter);
24707  * ```
24708  *
24709  * @property {Object.<string, function>} $validators A collection of validators that are applied
24710  *      whenever the model value changes. The key value within the object refers to the name of the
24711  *      validator while the function refers to the validation operation. The validation operation is
24712  *      provided with the model value as an argument and must return a true or false value depending
24713  *      on the response of that validation.
24714  *
24715  * ```js
24716  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
24717  *   var value = modelValue || viewValue;
24718  *   return /[0-9]+/.test(value) &&
24719  *          /[a-z]+/.test(value) &&
24720  *          /[A-Z]+/.test(value) &&
24721  *          /\W+/.test(value);
24722  * };
24723  * ```
24724  *
24725  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
24726  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
24727  *      is expected to return a promise when it is run during the model validation process. Once the promise
24728  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
24729  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
24730  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
24731  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
24732  *      will only run once all synchronous validators have passed.
24733  *
24734  * Please note that if $http is used then it is important that the server returns a success HTTP response code
24735  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
24736  *
24737  * ```js
24738  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
24739  *   var value = modelValue || viewValue;
24740  *
24741  *   // Lookup user by username
24742  *   return $http.get('/api/users/' + value).
24743  *      then(function resolved() {
24744  *        //username exists, this means validation fails
24745  *        return $q.reject('exists');
24746  *      }, function rejected() {
24747  *        //username does not exist, therefore this validation passes
24748  *        return true;
24749  *      });
24750  * };
24751  * ```
24752  *
24753  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
24754  *     view value has changed. It is called with no arguments, and its return value is ignored.
24755  *     This can be used in place of additional $watches against the model value.
24756  *
24757  * @property {Object} $error An object hash with all failing validator ids as keys.
24758  * @property {Object} $pending An object hash with all pending validator ids as keys.
24759  *
24760  * @property {boolean} $untouched True if control has not lost focus yet.
24761  * @property {boolean} $touched True if control has lost focus.
24762  * @property {boolean} $pristine True if user has not interacted with the control yet.
24763  * @property {boolean} $dirty True if user has already interacted with the control.
24764  * @property {boolean} $valid True if there is no error.
24765  * @property {boolean} $invalid True if at least one error on the control.
24766  * @property {string} $name The name attribute of the control.
24767  *
24768  * @description
24769  *
24770  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
24771  * The controller contains services for data-binding, validation, CSS updates, and value formatting
24772  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
24773  * listening to DOM events.
24774  * Such DOM related logic should be provided by other directives which make use of
24775  * `NgModelController` for data-binding to control elements.
24776  * Angular provides this DOM logic for most {@link input `input`} elements.
24777  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
24778  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
24779  *
24780  * @example
24781  * ### Custom Control Example
24782  * This example shows how to use `NgModelController` with a custom control to achieve
24783  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
24784  * collaborate together to achieve the desired result.
24785  *
24786  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
24787  * contents be edited in place by the user.
24788  *
24789  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
24790  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
24791  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
24792  * that content using the `$sce` service.
24793  *
24794  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
24795     <file name="style.css">
24796       [contenteditable] {
24797         border: 1px solid black;
24798         background-color: white;
24799         min-height: 20px;
24800       }
24801
24802       .ng-invalid {
24803         border: 1px solid red;
24804       }
24805
24806     </file>
24807     <file name="script.js">
24808       angular.module('customControl', ['ngSanitize']).
24809         directive('contenteditable', ['$sce', function($sce) {
24810           return {
24811             restrict: 'A', // only activate on element attribute
24812             require: '?ngModel', // get a hold of NgModelController
24813             link: function(scope, element, attrs, ngModel) {
24814               if (!ngModel) return; // do nothing if no ng-model
24815
24816               // Specify how UI should be updated
24817               ngModel.$render = function() {
24818                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
24819               };
24820
24821               // Listen for change events to enable binding
24822               element.on('blur keyup change', function() {
24823                 scope.$evalAsync(read);
24824               });
24825               read(); // initialize
24826
24827               // Write data to the model
24828               function read() {
24829                 var html = element.html();
24830                 // When we clear the content editable the browser leaves a <br> behind
24831                 // If strip-br attribute is provided then we strip this out
24832                 if ( attrs.stripBr && html == '<br>' ) {
24833                   html = '';
24834                 }
24835                 ngModel.$setViewValue(html);
24836               }
24837             }
24838           };
24839         }]);
24840     </file>
24841     <file name="index.html">
24842       <form name="myForm">
24843        <div contenteditable
24844             name="myWidget" ng-model="userContent"
24845             strip-br="true"
24846             required>Change me!</div>
24847         <span ng-show="myForm.myWidget.$error.required">Required!</span>
24848        <hr>
24849        <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
24850       </form>
24851     </file>
24852     <file name="protractor.js" type="protractor">
24853     it('should data-bind and become invalid', function() {
24854       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
24855         // SafariDriver can't handle contenteditable
24856         // and Firefox driver can't clear contenteditables very well
24857         return;
24858       }
24859       var contentEditable = element(by.css('[contenteditable]'));
24860       var content = 'Change me!';
24861
24862       expect(contentEditable.getText()).toEqual(content);
24863
24864       contentEditable.clear();
24865       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
24866       expect(contentEditable.getText()).toEqual('');
24867       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
24868     });
24869     </file>
24870  * </example>
24871  *
24872  *
24873  */
24874 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
24875     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
24876   this.$viewValue = Number.NaN;
24877   this.$modelValue = Number.NaN;
24878   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
24879   this.$validators = {};
24880   this.$asyncValidators = {};
24881   this.$parsers = [];
24882   this.$formatters = [];
24883   this.$viewChangeListeners = [];
24884   this.$untouched = true;
24885   this.$touched = false;
24886   this.$pristine = true;
24887   this.$dirty = false;
24888   this.$valid = true;
24889   this.$invalid = false;
24890   this.$error = {}; // keep invalid keys here
24891   this.$$success = {}; // keep valid keys here
24892   this.$pending = undefined; // keep pending keys here
24893   this.$name = $interpolate($attr.name || '', false)($scope);
24894   this.$$parentForm = nullFormCtrl;
24895
24896   var parsedNgModel = $parse($attr.ngModel),
24897       parsedNgModelAssign = parsedNgModel.assign,
24898       ngModelGet = parsedNgModel,
24899       ngModelSet = parsedNgModelAssign,
24900       pendingDebounce = null,
24901       parserValid,
24902       ctrl = this;
24903
24904   this.$$setOptions = function(options) {
24905     ctrl.$options = options;
24906     if (options && options.getterSetter) {
24907       var invokeModelGetter = $parse($attr.ngModel + '()'),
24908           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
24909
24910       ngModelGet = function($scope) {
24911         var modelValue = parsedNgModel($scope);
24912         if (isFunction(modelValue)) {
24913           modelValue = invokeModelGetter($scope);
24914         }
24915         return modelValue;
24916       };
24917       ngModelSet = function($scope, newValue) {
24918         if (isFunction(parsedNgModel($scope))) {
24919           invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
24920         } else {
24921           parsedNgModelAssign($scope, ctrl.$modelValue);
24922         }
24923       };
24924     } else if (!parsedNgModel.assign) {
24925       throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
24926           $attr.ngModel, startingTag($element));
24927     }
24928   };
24929
24930   /**
24931    * @ngdoc method
24932    * @name ngModel.NgModelController#$render
24933    *
24934    * @description
24935    * Called when the view needs to be updated. It is expected that the user of the ng-model
24936    * directive will implement this method.
24937    *
24938    * The `$render()` method is invoked in the following situations:
24939    *
24940    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
24941    *   committed value then `$render()` is called to update the input control.
24942    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
24943    *   the `$viewValue` are different from last time.
24944    *
24945    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
24946    * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
24947    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
24948    * invoked if you only change a property on the objects.
24949    */
24950   this.$render = noop;
24951
24952   /**
24953    * @ngdoc method
24954    * @name ngModel.NgModelController#$isEmpty
24955    *
24956    * @description
24957    * This is called when we need to determine if the value of an input is empty.
24958    *
24959    * For instance, the required directive does this to work out if the input has data or not.
24960    *
24961    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
24962    *
24963    * You can override this for input directives whose concept of being empty is different from the
24964    * default. The `checkboxInputType` directive does this because in its case a value of `false`
24965    * implies empty.
24966    *
24967    * @param {*} value The value of the input to check for emptiness.
24968    * @returns {boolean} True if `value` is "empty".
24969    */
24970   this.$isEmpty = function(value) {
24971     return isUndefined(value) || value === '' || value === null || value !== value;
24972   };
24973
24974   var currentValidationRunId = 0;
24975
24976   /**
24977    * @ngdoc method
24978    * @name ngModel.NgModelController#$setValidity
24979    *
24980    * @description
24981    * Change the validity state, and notify the form.
24982    *
24983    * This method can be called within $parsers/$formatters or a custom validation implementation.
24984    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
24985    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
24986    *
24987    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
24988    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
24989    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
24990    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
24991    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
24992    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
24993    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
24994    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
24995    *                          Skipped is used by Angular when validators do not run because of parse errors and
24996    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
24997    */
24998   addSetValidityMethod({
24999     ctrl: this,
25000     $element: $element,
25001     set: function(object, property) {
25002       object[property] = true;
25003     },
25004     unset: function(object, property) {
25005       delete object[property];
25006     },
25007     $animate: $animate
25008   });
25009
25010   /**
25011    * @ngdoc method
25012    * @name ngModel.NgModelController#$setPristine
25013    *
25014    * @description
25015    * Sets the control to its pristine state.
25016    *
25017    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
25018    * state (`ng-pristine` class). A model is considered to be pristine when the control
25019    * has not been changed from when first compiled.
25020    */
25021   this.$setPristine = function() {
25022     ctrl.$dirty = false;
25023     ctrl.$pristine = true;
25024     $animate.removeClass($element, DIRTY_CLASS);
25025     $animate.addClass($element, PRISTINE_CLASS);
25026   };
25027
25028   /**
25029    * @ngdoc method
25030    * @name ngModel.NgModelController#$setDirty
25031    *
25032    * @description
25033    * Sets the control to its dirty state.
25034    *
25035    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
25036    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
25037    * from when first compiled.
25038    */
25039   this.$setDirty = function() {
25040     ctrl.$dirty = true;
25041     ctrl.$pristine = false;
25042     $animate.removeClass($element, PRISTINE_CLASS);
25043     $animate.addClass($element, DIRTY_CLASS);
25044     ctrl.$$parentForm.$setDirty();
25045   };
25046
25047   /**
25048    * @ngdoc method
25049    * @name ngModel.NgModelController#$setUntouched
25050    *
25051    * @description
25052    * Sets the control to its untouched state.
25053    *
25054    * This method can be called to remove the `ng-touched` class and set the control to its
25055    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
25056    * by default, however this function can be used to restore that state if the model has
25057    * already been touched by the user.
25058    */
25059   this.$setUntouched = function() {
25060     ctrl.$touched = false;
25061     ctrl.$untouched = true;
25062     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
25063   };
25064
25065   /**
25066    * @ngdoc method
25067    * @name ngModel.NgModelController#$setTouched
25068    *
25069    * @description
25070    * Sets the control to its touched state.
25071    *
25072    * This method can be called to remove the `ng-untouched` class and set the control to its
25073    * touched state (`ng-touched` class). A model is considered to be touched when the user has
25074    * first focused the control element and then shifted focus away from the control (blur event).
25075    */
25076   this.$setTouched = function() {
25077     ctrl.$touched = true;
25078     ctrl.$untouched = false;
25079     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
25080   };
25081
25082   /**
25083    * @ngdoc method
25084    * @name ngModel.NgModelController#$rollbackViewValue
25085    *
25086    * @description
25087    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
25088    * which may be caused by a pending debounced event or because the input is waiting for a some
25089    * future event.
25090    *
25091    * If you have an input that uses `ng-model-options` to set up debounced events or events such
25092    * as blur you can have a situation where there is a period when the `$viewValue`
25093    * is out of synch with the ngModel's `$modelValue`.
25094    *
25095    * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
25096    * programmatically before these debounced/future events have resolved/occurred, because Angular's
25097    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
25098    *
25099    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
25100    * input which may have such events pending. This is important in order to make sure that the
25101    * input field will be updated with the new model value and any pending operations are cancelled.
25102    *
25103    * <example name="ng-model-cancel-update" module="cancel-update-example">
25104    *   <file name="app.js">
25105    *     angular.module('cancel-update-example', [])
25106    *
25107    *     .controller('CancelUpdateController', ['$scope', function($scope) {
25108    *       $scope.resetWithCancel = function(e) {
25109    *         if (e.keyCode == 27) {
25110    *           $scope.myForm.myInput1.$rollbackViewValue();
25111    *           $scope.myValue = '';
25112    *         }
25113    *       };
25114    *       $scope.resetWithoutCancel = function(e) {
25115    *         if (e.keyCode == 27) {
25116    *           $scope.myValue = '';
25117    *         }
25118    *       };
25119    *     }]);
25120    *   </file>
25121    *   <file name="index.html">
25122    *     <div ng-controller="CancelUpdateController">
25123    *       <p>Try typing something in each input.  See that the model only updates when you
25124    *          blur off the input.
25125    *        </p>
25126    *        <p>Now see what happens if you start typing then press the Escape key</p>
25127    *
25128    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
25129    *         <p id="inputDescription1">With $rollbackViewValue()</p>
25130    *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
25131    *                ng-keydown="resetWithCancel($event)"><br/>
25132    *         myValue: "{{ myValue }}"
25133    *
25134    *         <p id="inputDescription2">Without $rollbackViewValue()</p>
25135    *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
25136    *                ng-keydown="resetWithoutCancel($event)"><br/>
25137    *         myValue: "{{ myValue }}"
25138    *       </form>
25139    *     </div>
25140    *   </file>
25141    * </example>
25142    */
25143   this.$rollbackViewValue = function() {
25144     $timeout.cancel(pendingDebounce);
25145     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
25146     ctrl.$render();
25147   };
25148
25149   /**
25150    * @ngdoc method
25151    * @name ngModel.NgModelController#$validate
25152    *
25153    * @description
25154    * Runs each of the registered validators (first synchronous validators and then
25155    * asynchronous validators).
25156    * If the validity changes to invalid, the model will be set to `undefined`,
25157    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
25158    * If the validity changes to valid, it will set the model to the last available valid
25159    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
25160    */
25161   this.$validate = function() {
25162     // ignore $validate before model is initialized
25163     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25164       return;
25165     }
25166
25167     var viewValue = ctrl.$$lastCommittedViewValue;
25168     // Note: we use the $$rawModelValue as $modelValue might have been
25169     // set to undefined during a view -> model update that found validation
25170     // errors. We can't parse the view here, since that could change
25171     // the model although neither viewValue nor the model on the scope changed
25172     var modelValue = ctrl.$$rawModelValue;
25173
25174     var prevValid = ctrl.$valid;
25175     var prevModelValue = ctrl.$modelValue;
25176
25177     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25178
25179     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
25180       // If there was no change in validity, don't update the model
25181       // This prevents changing an invalid modelValue to undefined
25182       if (!allowInvalid && prevValid !== allValid) {
25183         // Note: Don't check ctrl.$valid here, as we could have
25184         // external validators (e.g. calculated on the server),
25185         // that just call $setValidity and need the model value
25186         // to calculate their validity.
25187         ctrl.$modelValue = allValid ? modelValue : undefined;
25188
25189         if (ctrl.$modelValue !== prevModelValue) {
25190           ctrl.$$writeModelToScope();
25191         }
25192       }
25193     });
25194
25195   };
25196
25197   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
25198     currentValidationRunId++;
25199     var localValidationRunId = currentValidationRunId;
25200
25201     // check parser error
25202     if (!processParseErrors()) {
25203       validationDone(false);
25204       return;
25205     }
25206     if (!processSyncValidators()) {
25207       validationDone(false);
25208       return;
25209     }
25210     processAsyncValidators();
25211
25212     function processParseErrors() {
25213       var errorKey = ctrl.$$parserName || 'parse';
25214       if (isUndefined(parserValid)) {
25215         setValidity(errorKey, null);
25216       } else {
25217         if (!parserValid) {
25218           forEach(ctrl.$validators, function(v, name) {
25219             setValidity(name, null);
25220           });
25221           forEach(ctrl.$asyncValidators, function(v, name) {
25222             setValidity(name, null);
25223           });
25224         }
25225         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
25226         setValidity(errorKey, parserValid);
25227         return parserValid;
25228       }
25229       return true;
25230     }
25231
25232     function processSyncValidators() {
25233       var syncValidatorsValid = true;
25234       forEach(ctrl.$validators, function(validator, name) {
25235         var result = validator(modelValue, viewValue);
25236         syncValidatorsValid = syncValidatorsValid && result;
25237         setValidity(name, result);
25238       });
25239       if (!syncValidatorsValid) {
25240         forEach(ctrl.$asyncValidators, function(v, name) {
25241           setValidity(name, null);
25242         });
25243         return false;
25244       }
25245       return true;
25246     }
25247
25248     function processAsyncValidators() {
25249       var validatorPromises = [];
25250       var allValid = true;
25251       forEach(ctrl.$asyncValidators, function(validator, name) {
25252         var promise = validator(modelValue, viewValue);
25253         if (!isPromiseLike(promise)) {
25254           throw ngModelMinErr("$asyncValidators",
25255             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
25256         }
25257         setValidity(name, undefined);
25258         validatorPromises.push(promise.then(function() {
25259           setValidity(name, true);
25260         }, function(error) {
25261           allValid = false;
25262           setValidity(name, false);
25263         }));
25264       });
25265       if (!validatorPromises.length) {
25266         validationDone(true);
25267       } else {
25268         $q.all(validatorPromises).then(function() {
25269           validationDone(allValid);
25270         }, noop);
25271       }
25272     }
25273
25274     function setValidity(name, isValid) {
25275       if (localValidationRunId === currentValidationRunId) {
25276         ctrl.$setValidity(name, isValid);
25277       }
25278     }
25279
25280     function validationDone(allValid) {
25281       if (localValidationRunId === currentValidationRunId) {
25282
25283         doneCallback(allValid);
25284       }
25285     }
25286   };
25287
25288   /**
25289    * @ngdoc method
25290    * @name ngModel.NgModelController#$commitViewValue
25291    *
25292    * @description
25293    * Commit a pending update to the `$modelValue`.
25294    *
25295    * Updates may be pending by a debounced event or because the input is waiting for a some future
25296    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
25297    * usually handles calling this in response to input events.
25298    */
25299   this.$commitViewValue = function() {
25300     var viewValue = ctrl.$viewValue;
25301
25302     $timeout.cancel(pendingDebounce);
25303
25304     // If the view value has not changed then we should just exit, except in the case where there is
25305     // a native validator on the element. In this case the validation state may have changed even though
25306     // the viewValue has stayed empty.
25307     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
25308       return;
25309     }
25310     ctrl.$$lastCommittedViewValue = viewValue;
25311
25312     // change to dirty
25313     if (ctrl.$pristine) {
25314       this.$setDirty();
25315     }
25316     this.$$parseAndValidate();
25317   };
25318
25319   this.$$parseAndValidate = function() {
25320     var viewValue = ctrl.$$lastCommittedViewValue;
25321     var modelValue = viewValue;
25322     parserValid = isUndefined(modelValue) ? undefined : true;
25323
25324     if (parserValid) {
25325       for (var i = 0; i < ctrl.$parsers.length; i++) {
25326         modelValue = ctrl.$parsers[i](modelValue);
25327         if (isUndefined(modelValue)) {
25328           parserValid = false;
25329           break;
25330         }
25331       }
25332     }
25333     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25334       // ctrl.$modelValue has not been touched yet...
25335       ctrl.$modelValue = ngModelGet($scope);
25336     }
25337     var prevModelValue = ctrl.$modelValue;
25338     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25339     ctrl.$$rawModelValue = modelValue;
25340
25341     if (allowInvalid) {
25342       ctrl.$modelValue = modelValue;
25343       writeToModelIfNeeded();
25344     }
25345
25346     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
25347     // This can happen if e.g. $setViewValue is called from inside a parser
25348     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
25349       if (!allowInvalid) {
25350         // Note: Don't check ctrl.$valid here, as we could have
25351         // external validators (e.g. calculated on the server),
25352         // that just call $setValidity and need the model value
25353         // to calculate their validity.
25354         ctrl.$modelValue = allValid ? modelValue : undefined;
25355         writeToModelIfNeeded();
25356       }
25357     });
25358
25359     function writeToModelIfNeeded() {
25360       if (ctrl.$modelValue !== prevModelValue) {
25361         ctrl.$$writeModelToScope();
25362       }
25363     }
25364   };
25365
25366   this.$$writeModelToScope = function() {
25367     ngModelSet($scope, ctrl.$modelValue);
25368     forEach(ctrl.$viewChangeListeners, function(listener) {
25369       try {
25370         listener();
25371       } catch (e) {
25372         $exceptionHandler(e);
25373       }
25374     });
25375   };
25376
25377   /**
25378    * @ngdoc method
25379    * @name ngModel.NgModelController#$setViewValue
25380    *
25381    * @description
25382    * Update the view value.
25383    *
25384    * This method should be called when a control wants to change the view value; typically,
25385    * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
25386    * directive calls it when the value of the input changes and {@link ng.directive:select select}
25387    * calls it when an option is selected.
25388    *
25389    * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
25390    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
25391    * value sent directly for processing, finally to be applied to `$modelValue` and then the
25392    * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
25393    * in the `$viewChangeListeners` list, are called.
25394    *
25395    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
25396    * and the `default` trigger is not listed, all those actions will remain pending until one of the
25397    * `updateOn` events is triggered on the DOM element.
25398    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
25399    * directive is used with a custom debounce for this particular event.
25400    * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
25401    * is specified, once the timer runs out.
25402    *
25403    * When used with standard inputs, the view value will always be a string (which is in some cases
25404    * parsed into another type, such as a `Date` object for `input[date]`.)
25405    * However, custom controls might also pass objects to this method. In this case, we should make
25406    * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
25407    * perform a deep watch of objects, it only looks for a change of identity. If you only change
25408    * the property of the object then ngModel will not realise that the object has changed and
25409    * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
25410    * not change properties of the copy once it has been passed to `$setViewValue`.
25411    * Otherwise you may cause the model value on the scope to change incorrectly.
25412    *
25413    * <div class="alert alert-info">
25414    * In any case, the value passed to the method should always reflect the current value
25415    * of the control. For example, if you are calling `$setViewValue` for an input element,
25416    * you should pass the input DOM value. Otherwise, the control and the scope model become
25417    * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
25418    * the control's DOM value in any way. If we want to change the control's DOM value
25419    * programmatically, we should update the `ngModel` scope expression. Its new value will be
25420    * picked up by the model controller, which will run it through the `$formatters`, `$render` it
25421    * to update the DOM, and finally call `$validate` on it.
25422    * </div>
25423    *
25424    * @param {*} value value from the view.
25425    * @param {string} trigger Event that triggered the update.
25426    */
25427   this.$setViewValue = function(value, trigger) {
25428     ctrl.$viewValue = value;
25429     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
25430       ctrl.$$debounceViewValueCommit(trigger);
25431     }
25432   };
25433
25434   this.$$debounceViewValueCommit = function(trigger) {
25435     var debounceDelay = 0,
25436         options = ctrl.$options,
25437         debounce;
25438
25439     if (options && isDefined(options.debounce)) {
25440       debounce = options.debounce;
25441       if (isNumber(debounce)) {
25442         debounceDelay = debounce;
25443       } else if (isNumber(debounce[trigger])) {
25444         debounceDelay = debounce[trigger];
25445       } else if (isNumber(debounce['default'])) {
25446         debounceDelay = debounce['default'];
25447       }
25448     }
25449
25450     $timeout.cancel(pendingDebounce);
25451     if (debounceDelay) {
25452       pendingDebounce = $timeout(function() {
25453         ctrl.$commitViewValue();
25454       }, debounceDelay);
25455     } else if ($rootScope.$$phase) {
25456       ctrl.$commitViewValue();
25457     } else {
25458       $scope.$apply(function() {
25459         ctrl.$commitViewValue();
25460       });
25461     }
25462   };
25463
25464   // model -> value
25465   // Note: we cannot use a normal scope.$watch as we want to detect the following:
25466   // 1. scope value is 'a'
25467   // 2. user enters 'b'
25468   // 3. ng-change kicks in and reverts scope value to 'a'
25469   //    -> scope value did not change since the last digest as
25470   //       ng-change executes in apply phase
25471   // 4. view should be changed back to 'a'
25472   $scope.$watch(function ngModelWatch() {
25473     var modelValue = ngModelGet($scope);
25474
25475     // if scope model value and ngModel value are out of sync
25476     // TODO(perf): why not move this to the action fn?
25477     if (modelValue !== ctrl.$modelValue &&
25478        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
25479        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
25480     ) {
25481       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
25482       parserValid = undefined;
25483
25484       var formatters = ctrl.$formatters,
25485           idx = formatters.length;
25486
25487       var viewValue = modelValue;
25488       while (idx--) {
25489         viewValue = formatters[idx](viewValue);
25490       }
25491       if (ctrl.$viewValue !== viewValue) {
25492         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
25493         ctrl.$render();
25494
25495         ctrl.$$runValidators(modelValue, viewValue, noop);
25496       }
25497     }
25498
25499     return modelValue;
25500   });
25501 }];
25502
25503
25504 /**
25505  * @ngdoc directive
25506  * @name ngModel
25507  *
25508  * @element input
25509  * @priority 1
25510  *
25511  * @description
25512  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
25513  * property on the scope using {@link ngModel.NgModelController NgModelController},
25514  * which is created and exposed by this directive.
25515  *
25516  * `ngModel` is responsible for:
25517  *
25518  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
25519  *   require.
25520  * - Providing validation behavior (i.e. required, number, email, url).
25521  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
25522  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
25523  * - Registering the control with its parent {@link ng.directive:form form}.
25524  *
25525  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
25526  * current scope. If the property doesn't already exist on this scope, it will be created
25527  * implicitly and added to the scope.
25528  *
25529  * For best practices on using `ngModel`, see:
25530  *
25531  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
25532  *
25533  * For basic examples, how to use `ngModel`, see:
25534  *
25535  *  - {@link ng.directive:input input}
25536  *    - {@link input[text] text}
25537  *    - {@link input[checkbox] checkbox}
25538  *    - {@link input[radio] radio}
25539  *    - {@link input[number] number}
25540  *    - {@link input[email] email}
25541  *    - {@link input[url] url}
25542  *    - {@link input[date] date}
25543  *    - {@link input[datetime-local] datetime-local}
25544  *    - {@link input[time] time}
25545  *    - {@link input[month] month}
25546  *    - {@link input[week] week}
25547  *  - {@link ng.directive:select select}
25548  *  - {@link ng.directive:textarea textarea}
25549  *
25550  * # CSS classes
25551  * The following CSS classes are added and removed on the associated input/select/textarea element
25552  * depending on the validity of the model.
25553  *
25554  *  - `ng-valid`: the model is valid
25555  *  - `ng-invalid`: the model is invalid
25556  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
25557  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
25558  *  - `ng-pristine`: the control hasn't been interacted with yet
25559  *  - `ng-dirty`: the control has been interacted with
25560  *  - `ng-touched`: the control has been blurred
25561  *  - `ng-untouched`: the control hasn't been blurred
25562  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
25563  *
25564  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25565  *
25566  * ## Animation Hooks
25567  *
25568  * Animations within models are triggered when any of the associated CSS classes are added and removed
25569  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
25570  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25571  * The animations that are triggered within ngModel are similar to how they work in ngClass and
25572  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
25573  *
25574  * The following example shows a simple way to utilize CSS transitions to style an input element
25575  * that has been rendered as invalid after it has been validated:
25576  *
25577  * <pre>
25578  * //be sure to include ngAnimate as a module to hook into more
25579  * //advanced animations
25580  * .my-input {
25581  *   transition:0.5s linear all;
25582  *   background: white;
25583  * }
25584  * .my-input.ng-invalid {
25585  *   background: red;
25586  *   color:white;
25587  * }
25588  * </pre>
25589  *
25590  * @example
25591  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
25592      <file name="index.html">
25593        <script>
25594         angular.module('inputExample', [])
25595           .controller('ExampleController', ['$scope', function($scope) {
25596             $scope.val = '1';
25597           }]);
25598        </script>
25599        <style>
25600          .my-input {
25601            transition:all linear 0.5s;
25602            background: transparent;
25603          }
25604          .my-input.ng-invalid {
25605            color:white;
25606            background: red;
25607          }
25608        </style>
25609        <p id="inputDescription">
25610         Update input to see transitions when valid/invalid.
25611         Integer is a valid value.
25612        </p>
25613        <form name="testForm" ng-controller="ExampleController">
25614          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
25615                 aria-describedby="inputDescription" />
25616        </form>
25617      </file>
25618  * </example>
25619  *
25620  * ## Binding to a getter/setter
25621  *
25622  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
25623  * function that returns a representation of the model when called with zero arguments, and sets
25624  * the internal state of a model when called with an argument. It's sometimes useful to use this
25625  * for models that have an internal representation that's different from what the model exposes
25626  * to the view.
25627  *
25628  * <div class="alert alert-success">
25629  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
25630  * frequently than other parts of your code.
25631  * </div>
25632  *
25633  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
25634  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
25635  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
25636  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
25637  *
25638  * The following example shows how to use `ngModel` with a getter/setter:
25639  *
25640  * @example
25641  * <example name="ngModel-getter-setter" module="getterSetterExample">
25642      <file name="index.html">
25643        <div ng-controller="ExampleController">
25644          <form name="userForm">
25645            <label>Name:
25646              <input type="text" name="userName"
25647                     ng-model="user.name"
25648                     ng-model-options="{ getterSetter: true }" />
25649            </label>
25650          </form>
25651          <pre>user.name = <span ng-bind="user.name()"></span></pre>
25652        </div>
25653      </file>
25654      <file name="app.js">
25655        angular.module('getterSetterExample', [])
25656          .controller('ExampleController', ['$scope', function($scope) {
25657            var _name = 'Brian';
25658            $scope.user = {
25659              name: function(newName) {
25660               // Note that newName can be undefined for two reasons:
25661               // 1. Because it is called as a getter and thus called with no arguments
25662               // 2. Because the property should actually be set to undefined. This happens e.g. if the
25663               //    input is invalid
25664               return arguments.length ? (_name = newName) : _name;
25665              }
25666            };
25667          }]);
25668      </file>
25669  * </example>
25670  */
25671 var ngModelDirective = ['$rootScope', function($rootScope) {
25672   return {
25673     restrict: 'A',
25674     require: ['ngModel', '^?form', '^?ngModelOptions'],
25675     controller: NgModelController,
25676     // Prelink needs to run before any input directive
25677     // so that we can set the NgModelOptions in NgModelController
25678     // before anyone else uses it.
25679     priority: 1,
25680     compile: function ngModelCompile(element) {
25681       // Setup initial state of the control
25682       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
25683
25684       return {
25685         pre: function ngModelPreLink(scope, element, attr, ctrls) {
25686           var modelCtrl = ctrls[0],
25687               formCtrl = ctrls[1] || modelCtrl.$$parentForm;
25688
25689           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
25690
25691           // notify others, especially parent forms
25692           formCtrl.$addControl(modelCtrl);
25693
25694           attr.$observe('name', function(newValue) {
25695             if (modelCtrl.$name !== newValue) {
25696               modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
25697             }
25698           });
25699
25700           scope.$on('$destroy', function() {
25701             modelCtrl.$$parentForm.$removeControl(modelCtrl);
25702           });
25703         },
25704         post: function ngModelPostLink(scope, element, attr, ctrls) {
25705           var modelCtrl = ctrls[0];
25706           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
25707             element.on(modelCtrl.$options.updateOn, function(ev) {
25708               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
25709             });
25710           }
25711
25712           element.on('blur', function(ev) {
25713             if (modelCtrl.$touched) return;
25714
25715             if ($rootScope.$$phase) {
25716               scope.$evalAsync(modelCtrl.$setTouched);
25717             } else {
25718               scope.$apply(modelCtrl.$setTouched);
25719             }
25720           });
25721         }
25722       };
25723     }
25724   };
25725 }];
25726
25727 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25728
25729 /**
25730  * @ngdoc directive
25731  * @name ngModelOptions
25732  *
25733  * @description
25734  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
25735  * events that will trigger a model update and/or a debouncing delay so that the actual update only
25736  * takes place when a timer expires; this timer will be reset after another change takes place.
25737  *
25738  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
25739  * be different from the value in the actual model. This means that if you update the model you
25740  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
25741  * order to make sure it is synchronized with the model and that any debounced action is canceled.
25742  *
25743  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
25744  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
25745  * important because `form` controllers are published to the related scope under the name in their
25746  * `name` attribute.
25747  *
25748  * Any pending changes will take place immediately when an enclosing form is submitted via the
25749  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25750  * to have access to the updated model.
25751  *
25752  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
25753  *
25754  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
25755  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
25756  *     events using an space delimited list. There is a special event called `default` that
25757  *     matches the default events belonging of the control.
25758  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
25759  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
25760  *     custom value for each event. For example:
25761  *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
25762  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
25763  *     not validate correctly instead of the default behavior of setting the model to undefined.
25764  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
25765        `ngModel` as getters/setters.
25766  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
25767  *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
25768  *     continental US time zone abbreviations, but for general use, use a time zone offset, for
25769  *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25770  *     If not specified, the timezone of the browser will be used.
25771  *
25772  * @example
25773
25774   The following example shows how to override immediate updates. Changes on the inputs within the
25775   form will update the model only when the control loses focus (blur event). If `escape` key is
25776   pressed while the input field is focused, the value is reset to the value in the current model.
25777
25778   <example name="ngModelOptions-directive-blur" module="optionsExample">
25779     <file name="index.html">
25780       <div ng-controller="ExampleController">
25781         <form name="userForm">
25782           <label>Name:
25783             <input type="text" name="userName"
25784                    ng-model="user.name"
25785                    ng-model-options="{ updateOn: 'blur' }"
25786                    ng-keyup="cancel($event)" />
25787           </label><br />
25788           <label>Other data:
25789             <input type="text" ng-model="user.data" />
25790           </label><br />
25791         </form>
25792         <pre>user.name = <span ng-bind="user.name"></span></pre>
25793         <pre>user.data = <span ng-bind="user.data"></span></pre>
25794       </div>
25795     </file>
25796     <file name="app.js">
25797       angular.module('optionsExample', [])
25798         .controller('ExampleController', ['$scope', function($scope) {
25799           $scope.user = { name: 'John', data: '' };
25800
25801           $scope.cancel = function(e) {
25802             if (e.keyCode == 27) {
25803               $scope.userForm.userName.$rollbackViewValue();
25804             }
25805           };
25806         }]);
25807     </file>
25808     <file name="protractor.js" type="protractor">
25809       var model = element(by.binding('user.name'));
25810       var input = element(by.model('user.name'));
25811       var other = element(by.model('user.data'));
25812
25813       it('should allow custom events', function() {
25814         input.sendKeys(' Doe');
25815         input.click();
25816         expect(model.getText()).toEqual('John');
25817         other.click();
25818         expect(model.getText()).toEqual('John Doe');
25819       });
25820
25821       it('should $rollbackViewValue when model changes', function() {
25822         input.sendKeys(' Doe');
25823         expect(input.getAttribute('value')).toEqual('John Doe');
25824         input.sendKeys(protractor.Key.ESCAPE);
25825         expect(input.getAttribute('value')).toEqual('John');
25826         other.click();
25827         expect(model.getText()).toEqual('John');
25828       });
25829     </file>
25830   </example>
25831
25832   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
25833   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
25834
25835   <example name="ngModelOptions-directive-debounce" module="optionsExample">
25836     <file name="index.html">
25837       <div ng-controller="ExampleController">
25838         <form name="userForm">
25839           <label>Name:
25840             <input type="text" name="userName"
25841                    ng-model="user.name"
25842                    ng-model-options="{ debounce: 1000 }" />
25843           </label>
25844           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
25845           <br />
25846         </form>
25847         <pre>user.name = <span ng-bind="user.name"></span></pre>
25848       </div>
25849     </file>
25850     <file name="app.js">
25851       angular.module('optionsExample', [])
25852         .controller('ExampleController', ['$scope', function($scope) {
25853           $scope.user = { name: 'Igor' };
25854         }]);
25855     </file>
25856   </example>
25857
25858   This one shows how to bind to getter/setters:
25859
25860   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
25861     <file name="index.html">
25862       <div ng-controller="ExampleController">
25863         <form name="userForm">
25864           <label>Name:
25865             <input type="text" name="userName"
25866                    ng-model="user.name"
25867                    ng-model-options="{ getterSetter: true }" />
25868           </label>
25869         </form>
25870         <pre>user.name = <span ng-bind="user.name()"></span></pre>
25871       </div>
25872     </file>
25873     <file name="app.js">
25874       angular.module('getterSetterExample', [])
25875         .controller('ExampleController', ['$scope', function($scope) {
25876           var _name = 'Brian';
25877           $scope.user = {
25878             name: function(newName) {
25879               // Note that newName can be undefined for two reasons:
25880               // 1. Because it is called as a getter and thus called with no arguments
25881               // 2. Because the property should actually be set to undefined. This happens e.g. if the
25882               //    input is invalid
25883               return arguments.length ? (_name = newName) : _name;
25884             }
25885           };
25886         }]);
25887     </file>
25888   </example>
25889  */
25890 var ngModelOptionsDirective = function() {
25891   return {
25892     restrict: 'A',
25893     controller: ['$scope', '$attrs', function($scope, $attrs) {
25894       var that = this;
25895       this.$options = copy($scope.$eval($attrs.ngModelOptions));
25896       // Allow adding/overriding bound events
25897       if (isDefined(this.$options.updateOn)) {
25898         this.$options.updateOnDefault = false;
25899         // extract "default" pseudo-event from list of events that can trigger a model update
25900         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
25901           that.$options.updateOnDefault = true;
25902           return ' ';
25903         }));
25904       } else {
25905         this.$options.updateOnDefault = true;
25906       }
25907     }]
25908   };
25909 };
25910
25911
25912
25913 // helper methods
25914 function addSetValidityMethod(context) {
25915   var ctrl = context.ctrl,
25916       $element = context.$element,
25917       classCache = {},
25918       set = context.set,
25919       unset = context.unset,
25920       $animate = context.$animate;
25921
25922   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
25923
25924   ctrl.$setValidity = setValidity;
25925
25926   function setValidity(validationErrorKey, state, controller) {
25927     if (isUndefined(state)) {
25928       createAndSet('$pending', validationErrorKey, controller);
25929     } else {
25930       unsetAndCleanup('$pending', validationErrorKey, controller);
25931     }
25932     if (!isBoolean(state)) {
25933       unset(ctrl.$error, validationErrorKey, controller);
25934       unset(ctrl.$$success, validationErrorKey, controller);
25935     } else {
25936       if (state) {
25937         unset(ctrl.$error, validationErrorKey, controller);
25938         set(ctrl.$$success, validationErrorKey, controller);
25939       } else {
25940         set(ctrl.$error, validationErrorKey, controller);
25941         unset(ctrl.$$success, validationErrorKey, controller);
25942       }
25943     }
25944     if (ctrl.$pending) {
25945       cachedToggleClass(PENDING_CLASS, true);
25946       ctrl.$valid = ctrl.$invalid = undefined;
25947       toggleValidationCss('', null);
25948     } else {
25949       cachedToggleClass(PENDING_CLASS, false);
25950       ctrl.$valid = isObjectEmpty(ctrl.$error);
25951       ctrl.$invalid = !ctrl.$valid;
25952       toggleValidationCss('', ctrl.$valid);
25953     }
25954
25955     // re-read the state as the set/unset methods could have
25956     // combined state in ctrl.$error[validationError] (used for forms),
25957     // where setting/unsetting only increments/decrements the value,
25958     // and does not replace it.
25959     var combinedState;
25960     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
25961       combinedState = undefined;
25962     } else if (ctrl.$error[validationErrorKey]) {
25963       combinedState = false;
25964     } else if (ctrl.$$success[validationErrorKey]) {
25965       combinedState = true;
25966     } else {
25967       combinedState = null;
25968     }
25969
25970     toggleValidationCss(validationErrorKey, combinedState);
25971     ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
25972   }
25973
25974   function createAndSet(name, value, controller) {
25975     if (!ctrl[name]) {
25976       ctrl[name] = {};
25977     }
25978     set(ctrl[name], value, controller);
25979   }
25980
25981   function unsetAndCleanup(name, value, controller) {
25982     if (ctrl[name]) {
25983       unset(ctrl[name], value, controller);
25984     }
25985     if (isObjectEmpty(ctrl[name])) {
25986       ctrl[name] = undefined;
25987     }
25988   }
25989
25990   function cachedToggleClass(className, switchValue) {
25991     if (switchValue && !classCache[className]) {
25992       $animate.addClass($element, className);
25993       classCache[className] = true;
25994     } else if (!switchValue && classCache[className]) {
25995       $animate.removeClass($element, className);
25996       classCache[className] = false;
25997     }
25998   }
25999
26000   function toggleValidationCss(validationErrorKey, isValid) {
26001     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
26002
26003     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
26004     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
26005   }
26006 }
26007
26008 function isObjectEmpty(obj) {
26009   if (obj) {
26010     for (var prop in obj) {
26011       if (obj.hasOwnProperty(prop)) {
26012         return false;
26013       }
26014     }
26015   }
26016   return true;
26017 }
26018
26019 /**
26020  * @ngdoc directive
26021  * @name ngNonBindable
26022  * @restrict AC
26023  * @priority 1000
26024  *
26025  * @description
26026  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
26027  * DOM element. This is useful if the element contains what appears to be Angular directives and
26028  * bindings but which should be ignored by Angular. This could be the case if you have a site that
26029  * displays snippets of code, for instance.
26030  *
26031  * @element ANY
26032  *
26033  * @example
26034  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
26035  * but the one wrapped in `ngNonBindable` is left alone.
26036  *
26037  * @example
26038     <example>
26039       <file name="index.html">
26040         <div>Normal: {{1 + 2}}</div>
26041         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
26042       </file>
26043       <file name="protractor.js" type="protractor">
26044        it('should check ng-non-bindable', function() {
26045          expect(element(by.binding('1 + 2')).getText()).toContain('3');
26046          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
26047        });
26048       </file>
26049     </example>
26050  */
26051 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
26052
26053 /* global jqLiteRemove */
26054
26055 var ngOptionsMinErr = minErr('ngOptions');
26056
26057 /**
26058  * @ngdoc directive
26059  * @name ngOptions
26060  * @restrict A
26061  *
26062  * @description
26063  *
26064  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
26065  * elements for the `<select>` element using the array or object obtained by evaluating the
26066  * `ngOptions` comprehension expression.
26067  *
26068  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
26069  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
26070  * increasing speed by not creating a new scope for each repeated instance, as well as providing
26071  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
26072  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
26073  *  to a non-string value. This is because an option element can only be bound to string values at
26074  * present.
26075  *
26076  * When an item in the `<select>` menu is selected, the array element or object property
26077  * represented by the selected option will be bound to the model identified by the `ngModel`
26078  * directive.
26079  *
26080  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
26081  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
26082  * option. See example below for demonstration.
26083  *
26084  * ## Complex Models (objects or collections)
26085  *
26086  * By default, `ngModel` watches the model by reference, not value. This is important to know when
26087  * binding the select to a model that is an object or a collection.
26088  *
26089  * One issue occurs if you want to preselect an option. For example, if you set
26090  * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
26091  * because the objects are not identical. So by default, you should always reference the item in your collection
26092  * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
26093  *
26094  * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
26095  * of the item not by reference, but by the result of the `track by` expression. For example, if your
26096  * collection items have an id property, you would `track by item.id`.
26097  *
26098  * A different issue with objects or collections is that ngModel won't detect if an object property or
26099  * a collection item changes. For that reason, `ngOptions` additionally watches the model using
26100  * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
26101  * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
26102  * has not changed identity, but only a property on the object or an item in the collection changes.
26103  *
26104  * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26105  * if the model is an array). This means that changing a property deeper than the first level inside the
26106  * object/collection will not trigger a re-rendering.
26107  *
26108  * ## `select` **`as`**
26109  *
26110  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
26111  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
26112  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
26113  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
26114  *
26115  *
26116  * ### `select` **`as`** and **`track by`**
26117  *
26118  * <div class="alert alert-warning">
26119  * Be careful when using `select` **`as`** and **`track by`** in the same expression.
26120  * </div>
26121  *
26122  * Given this array of items on the $scope:
26123  *
26124  * ```js
26125  * $scope.items = [{
26126  *   id: 1,
26127  *   label: 'aLabel',
26128  *   subItem: { name: 'aSubItem' }
26129  * }, {
26130  *   id: 2,
26131  *   label: 'bLabel',
26132  *   subItem: { name: 'bSubItem' }
26133  * }];
26134  * ```
26135  *
26136  * This will work:
26137  *
26138  * ```html
26139  * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
26140  * ```
26141  * ```js
26142  * $scope.selected = $scope.items[0];
26143  * ```
26144  *
26145  * but this will not work:
26146  *
26147  * ```html
26148  * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
26149  * ```
26150  * ```js
26151  * $scope.selected = $scope.items[0].subItem;
26152  * ```
26153  *
26154  * In both examples, the **`track by`** expression is applied successfully to each `item` in the
26155  * `items` array. Because the selected option has been set programmatically in the controller, the
26156  * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
26157  * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
26158  * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
26159  * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
26160  * is not matched against any `<option>` and the `<select>` appears as having no selected value.
26161  *
26162  *
26163  * @param {string} ngModel Assignable angular expression to data-bind to.
26164  * @param {string=} name Property name of the form under which the control is published.
26165  * @param {string=} required The control is considered valid only if value is entered.
26166  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26167  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26168  *    `required` when you want to data-bind to the `required` attribute.
26169  * @param {comprehension_expression=} ngOptions in one of the following forms:
26170  *
26171  *   * for array data sources:
26172  *     * `label` **`for`** `value` **`in`** `array`
26173  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
26174  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
26175  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
26176  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26177  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26178  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
26179  *        (for including a filter with `track by`)
26180  *   * for object data sources:
26181  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26182  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26183  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
26184  *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
26185  *     * `select` **`as`** `label` **`group by`** `group`
26186  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26187  *     * `select` **`as`** `label` **`disable when`** `disable`
26188  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26189  *
26190  * Where:
26191  *
26192  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
26193  *   * `value`: local variable which will refer to each item in the `array` or each property value
26194  *      of `object` during iteration.
26195  *   * `key`: local variable which will refer to a property name in `object` during iteration.
26196  *   * `label`: The result of this expression will be the label for `<option>` element. The
26197  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
26198  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
26199  *      element. If not specified, `select` expression will default to `value`.
26200  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
26201  *      DOM element.
26202  *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
26203  *      element. Return `true` to disable.
26204  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
26205  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
26206  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
26207  *      even when the options are recreated (e.g. reloaded from the server).
26208  *
26209  * @example
26210     <example module="selectExample">
26211       <file name="index.html">
26212         <script>
26213         angular.module('selectExample', [])
26214           .controller('ExampleController', ['$scope', function($scope) {
26215             $scope.colors = [
26216               {name:'black', shade:'dark'},
26217               {name:'white', shade:'light', notAnOption: true},
26218               {name:'red', shade:'dark'},
26219               {name:'blue', shade:'dark', notAnOption: true},
26220               {name:'yellow', shade:'light', notAnOption: false}
26221             ];
26222             $scope.myColor = $scope.colors[2]; // red
26223           }]);
26224         </script>
26225         <div ng-controller="ExampleController">
26226           <ul>
26227             <li ng-repeat="color in colors">
26228               <label>Name: <input ng-model="color.name"></label>
26229               <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
26230               <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
26231             </li>
26232             <li>
26233               <button ng-click="colors.push({})">add</button>
26234             </li>
26235           </ul>
26236           <hr/>
26237           <label>Color (null not allowed):
26238             <select ng-model="myColor" ng-options="color.name for color in colors"></select>
26239           </label><br/>
26240           <label>Color (null allowed):
26241           <span  class="nullable">
26242             <select ng-model="myColor" ng-options="color.name for color in colors">
26243               <option value="">-- choose color --</option>
26244             </select>
26245           </span></label><br/>
26246
26247           <label>Color grouped by shade:
26248             <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
26249             </select>
26250           </label><br/>
26251
26252           <label>Color grouped by shade, with some disabled:
26253             <select ng-model="myColor"
26254                   ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
26255             </select>
26256           </label><br/>
26257
26258
26259
26260           Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
26261           <br/>
26262           <hr/>
26263           Currently selected: {{ {selected_color:myColor} }}
26264           <div style="border:solid 1px black; height:20px"
26265                ng-style="{'background-color':myColor.name}">
26266           </div>
26267         </div>
26268       </file>
26269       <file name="protractor.js" type="protractor">
26270          it('should check ng-options', function() {
26271            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
26272            element.all(by.model('myColor')).first().click();
26273            element.all(by.css('select[ng-model="myColor"] option')).first().click();
26274            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
26275            element(by.css('.nullable select[ng-model="myColor"]')).click();
26276            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
26277            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
26278          });
26279       </file>
26280     </example>
26281  */
26282
26283 // jshint maxlen: false
26284 //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
26285 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]+?))?$/;
26286                         // 1: value expression (valueFn)
26287                         // 2: label expression (displayFn)
26288                         // 3: group by expression (groupByFn)
26289                         // 4: disable when expression (disableWhenFn)
26290                         // 5: array item variable name
26291                         // 6: object item key variable name
26292                         // 7: object item value variable name
26293                         // 8: collection expression
26294                         // 9: track by expression
26295 // jshint maxlen: 100
26296
26297
26298 var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26299
26300   function parseOptionsExpression(optionsExp, selectElement, scope) {
26301
26302     var match = optionsExp.match(NG_OPTIONS_REGEXP);
26303     if (!(match)) {
26304       throw ngOptionsMinErr('iexp',
26305         "Expected expression in form of " +
26306         "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
26307         " but got '{0}'. Element: {1}",
26308         optionsExp, startingTag(selectElement));
26309     }
26310
26311     // Extract the parts from the ngOptions expression
26312
26313     // The variable name for the value of the item in the collection
26314     var valueName = match[5] || match[7];
26315     // The variable name for the key of the item in the collection
26316     var keyName = match[6];
26317
26318     // An expression that generates the viewValue for an option if there is a label expression
26319     var selectAs = / as /.test(match[0]) && match[1];
26320     // An expression that is used to track the id of each object in the options collection
26321     var trackBy = match[9];
26322     // An expression that generates the viewValue for an option if there is no label expression
26323     var valueFn = $parse(match[2] ? match[1] : valueName);
26324     var selectAsFn = selectAs && $parse(selectAs);
26325     var viewValueFn = selectAsFn || valueFn;
26326     var trackByFn = trackBy && $parse(trackBy);
26327
26328     // Get the value by which we are going to track the option
26329     // if we have a trackFn then use that (passing scope and locals)
26330     // otherwise just hash the given viewValue
26331     var getTrackByValueFn = trackBy ?
26332                               function(value, locals) { return trackByFn(scope, locals); } :
26333                               function getHashOfValue(value) { return hashKey(value); };
26334     var getTrackByValue = function(value, key) {
26335       return getTrackByValueFn(value, getLocals(value, key));
26336     };
26337
26338     var displayFn = $parse(match[2] || match[1]);
26339     var groupByFn = $parse(match[3] || '');
26340     var disableWhenFn = $parse(match[4] || '');
26341     var valuesFn = $parse(match[8]);
26342
26343     var locals = {};
26344     var getLocals = keyName ? function(value, key) {
26345       locals[keyName] = key;
26346       locals[valueName] = value;
26347       return locals;
26348     } : function(value) {
26349       locals[valueName] = value;
26350       return locals;
26351     };
26352
26353
26354     function Option(selectValue, viewValue, label, group, disabled) {
26355       this.selectValue = selectValue;
26356       this.viewValue = viewValue;
26357       this.label = label;
26358       this.group = group;
26359       this.disabled = disabled;
26360     }
26361
26362     function getOptionValuesKeys(optionValues) {
26363       var optionValuesKeys;
26364
26365       if (!keyName && isArrayLike(optionValues)) {
26366         optionValuesKeys = optionValues;
26367       } else {
26368         // if object, extract keys, in enumeration order, unsorted
26369         optionValuesKeys = [];
26370         for (var itemKey in optionValues) {
26371           if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
26372             optionValuesKeys.push(itemKey);
26373           }
26374         }
26375       }
26376       return optionValuesKeys;
26377     }
26378
26379     return {
26380       trackBy: trackBy,
26381       getTrackByValue: getTrackByValue,
26382       getWatchables: $parse(valuesFn, function(optionValues) {
26383         // Create a collection of things that we would like to watch (watchedArray)
26384         // so that they can all be watched using a single $watchCollection
26385         // that only runs the handler once if anything changes
26386         var watchedArray = [];
26387         optionValues = optionValues || [];
26388
26389         var optionValuesKeys = getOptionValuesKeys(optionValues);
26390         var optionValuesLength = optionValuesKeys.length;
26391         for (var index = 0; index < optionValuesLength; index++) {
26392           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26393           var value = optionValues[key];
26394
26395           var locals = getLocals(optionValues[key], key);
26396           var selectValue = getTrackByValueFn(optionValues[key], locals);
26397           watchedArray.push(selectValue);
26398
26399           // Only need to watch the displayFn if there is a specific label expression
26400           if (match[2] || match[1]) {
26401             var label = displayFn(scope, locals);
26402             watchedArray.push(label);
26403           }
26404
26405           // Only need to watch the disableWhenFn if there is a specific disable expression
26406           if (match[4]) {
26407             var disableWhen = disableWhenFn(scope, locals);
26408             watchedArray.push(disableWhen);
26409           }
26410         }
26411         return watchedArray;
26412       }),
26413
26414       getOptions: function() {
26415
26416         var optionItems = [];
26417         var selectValueMap = {};
26418
26419         // The option values were already computed in the `getWatchables` fn,
26420         // which must have been called to trigger `getOptions`
26421         var optionValues = valuesFn(scope) || [];
26422         var optionValuesKeys = getOptionValuesKeys(optionValues);
26423         var optionValuesLength = optionValuesKeys.length;
26424
26425         for (var index = 0; index < optionValuesLength; index++) {
26426           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26427           var value = optionValues[key];
26428           var locals = getLocals(value, key);
26429           var viewValue = viewValueFn(scope, locals);
26430           var selectValue = getTrackByValueFn(viewValue, locals);
26431           var label = displayFn(scope, locals);
26432           var group = groupByFn(scope, locals);
26433           var disabled = disableWhenFn(scope, locals);
26434           var optionItem = new Option(selectValue, viewValue, label, group, disabled);
26435
26436           optionItems.push(optionItem);
26437           selectValueMap[selectValue] = optionItem;
26438         }
26439
26440         return {
26441           items: optionItems,
26442           selectValueMap: selectValueMap,
26443           getOptionFromViewValue: function(value) {
26444             return selectValueMap[getTrackByValue(value)];
26445           },
26446           getViewValueFromOption: function(option) {
26447             // If the viewValue could be an object that may be mutated by the application,
26448             // we need to make a copy and not return the reference to the value on the option.
26449             return trackBy ? angular.copy(option.viewValue) : option.viewValue;
26450           }
26451         };
26452       }
26453     };
26454   }
26455
26456
26457   // we can't just jqLite('<option>') since jqLite is not smart enough
26458   // to create it in <select> and IE barfs otherwise.
26459   var optionTemplate = document.createElement('option'),
26460       optGroupTemplate = document.createElement('optgroup');
26461
26462
26463     function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26464
26465       // if ngModel is not defined, we don't need to do anything
26466       var ngModelCtrl = ctrls[1];
26467       if (!ngModelCtrl) return;
26468
26469       var selectCtrl = ctrls[0];
26470       var multiple = attr.multiple;
26471
26472       // The emptyOption allows the application developer to provide their own custom "empty"
26473       // option when the viewValue does not match any of the option values.
26474       var emptyOption;
26475       for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
26476         if (children[i].value === '') {
26477           emptyOption = children.eq(i);
26478           break;
26479         }
26480       }
26481
26482       var providedEmptyOption = !!emptyOption;
26483
26484       var unknownOption = jqLite(optionTemplate.cloneNode(false));
26485       unknownOption.val('?');
26486
26487       var options;
26488       var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
26489
26490
26491       var renderEmptyOption = function() {
26492         if (!providedEmptyOption) {
26493           selectElement.prepend(emptyOption);
26494         }
26495         selectElement.val('');
26496         emptyOption.prop('selected', true); // needed for IE
26497         emptyOption.attr('selected', true);
26498       };
26499
26500       var removeEmptyOption = function() {
26501         if (!providedEmptyOption) {
26502           emptyOption.remove();
26503         }
26504       };
26505
26506
26507       var renderUnknownOption = function() {
26508         selectElement.prepend(unknownOption);
26509         selectElement.val('?');
26510         unknownOption.prop('selected', true); // needed for IE
26511         unknownOption.attr('selected', true);
26512       };
26513
26514       var removeUnknownOption = function() {
26515         unknownOption.remove();
26516       };
26517
26518       // Update the controller methods for multiple selectable options
26519       if (!multiple) {
26520
26521         selectCtrl.writeValue = function writeNgOptionsValue(value) {
26522           var option = options.getOptionFromViewValue(value);
26523
26524           if (option && !option.disabled) {
26525             if (selectElement[0].value !== option.selectValue) {
26526               removeUnknownOption();
26527               removeEmptyOption();
26528
26529               selectElement[0].value = option.selectValue;
26530               option.element.selected = true;
26531               option.element.setAttribute('selected', 'selected');
26532             }
26533           } else {
26534             if (value === null || providedEmptyOption) {
26535               removeUnknownOption();
26536               renderEmptyOption();
26537             } else {
26538               removeEmptyOption();
26539               renderUnknownOption();
26540             }
26541           }
26542         };
26543
26544         selectCtrl.readValue = function readNgOptionsValue() {
26545
26546           var selectedOption = options.selectValueMap[selectElement.val()];
26547
26548           if (selectedOption && !selectedOption.disabled) {
26549             removeEmptyOption();
26550             removeUnknownOption();
26551             return options.getViewValueFromOption(selectedOption);
26552           }
26553           return null;
26554         };
26555
26556         // If we are using `track by` then we must watch the tracked value on the model
26557         // since ngModel only watches for object identity change
26558         if (ngOptions.trackBy) {
26559           scope.$watch(
26560             function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
26561             function() { ngModelCtrl.$render(); }
26562           );
26563         }
26564
26565       } else {
26566
26567         ngModelCtrl.$isEmpty = function(value) {
26568           return !value || value.length === 0;
26569         };
26570
26571
26572         selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
26573           options.items.forEach(function(option) {
26574             option.element.selected = false;
26575           });
26576
26577           if (value) {
26578             value.forEach(function(item) {
26579               var option = options.getOptionFromViewValue(item);
26580               if (option && !option.disabled) option.element.selected = true;
26581             });
26582           }
26583         };
26584
26585
26586         selectCtrl.readValue = function readNgOptionsMultiple() {
26587           var selectedValues = selectElement.val() || [],
26588               selections = [];
26589
26590           forEach(selectedValues, function(value) {
26591             var option = options.selectValueMap[value];
26592             if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
26593           });
26594
26595           return selections;
26596         };
26597
26598         // If we are using `track by` then we must watch these tracked values on the model
26599         // since ngModel only watches for object identity change
26600         if (ngOptions.trackBy) {
26601
26602           scope.$watchCollection(function() {
26603             if (isArray(ngModelCtrl.$viewValue)) {
26604               return ngModelCtrl.$viewValue.map(function(value) {
26605                 return ngOptions.getTrackByValue(value);
26606               });
26607             }
26608           }, function() {
26609             ngModelCtrl.$render();
26610           });
26611
26612         }
26613       }
26614
26615
26616       if (providedEmptyOption) {
26617
26618         // we need to remove it before calling selectElement.empty() because otherwise IE will
26619         // remove the label from the element. wtf?
26620         emptyOption.remove();
26621
26622         // compile the element since there might be bindings in it
26623         $compile(emptyOption)(scope);
26624
26625         // remove the class, which is added automatically because we recompile the element and it
26626         // becomes the compilation root
26627         emptyOption.removeClass('ng-scope');
26628       } else {
26629         emptyOption = jqLite(optionTemplate.cloneNode(false));
26630       }
26631
26632       // We need to do this here to ensure that the options object is defined
26633       // when we first hit it in writeNgOptionsValue
26634       updateOptions();
26635
26636       // We will re-render the option elements if the option values or labels change
26637       scope.$watchCollection(ngOptions.getWatchables, updateOptions);
26638
26639       // ------------------------------------------------------------------ //
26640
26641
26642       function updateOptionElement(option, element) {
26643         option.element = element;
26644         element.disabled = option.disabled;
26645         // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
26646         // selects in certain circumstances when multiple selects are next to each other and display
26647         // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
26648         // See https://github.com/angular/angular.js/issues/11314 for more info.
26649         // This is unfortunately untestable with unit / e2e tests
26650         if (option.label !== element.label) {
26651           element.label = option.label;
26652           element.textContent = option.label;
26653         }
26654         if (option.value !== element.value) element.value = option.selectValue;
26655       }
26656
26657       function addOrReuseElement(parent, current, type, templateElement) {
26658         var element;
26659         // Check whether we can reuse the next element
26660         if (current && lowercase(current.nodeName) === type) {
26661           // The next element is the right type so reuse it
26662           element = current;
26663         } else {
26664           // The next element is not the right type so create a new one
26665           element = templateElement.cloneNode(false);
26666           if (!current) {
26667             // There are no more elements so just append it to the select
26668             parent.appendChild(element);
26669           } else {
26670             // The next element is not a group so insert the new one
26671             parent.insertBefore(element, current);
26672           }
26673         }
26674         return element;
26675       }
26676
26677
26678       function removeExcessElements(current) {
26679         var next;
26680         while (current) {
26681           next = current.nextSibling;
26682           jqLiteRemove(current);
26683           current = next;
26684         }
26685       }
26686
26687
26688       function skipEmptyAndUnknownOptions(current) {
26689         var emptyOption_ = emptyOption && emptyOption[0];
26690         var unknownOption_ = unknownOption && unknownOption[0];
26691
26692         // We cannot rely on the extracted empty option being the same as the compiled empty option,
26693         // because the compiled empty option might have been replaced by a comment because
26694         // it had an "element" transclusion directive on it (such as ngIf)
26695         if (emptyOption_ || unknownOption_) {
26696           while (current &&
26697                 (current === emptyOption_ ||
26698                 current === unknownOption_ ||
26699                 current.nodeType === NODE_TYPE_COMMENT ||
26700                 current.value === '')) {
26701             current = current.nextSibling;
26702           }
26703         }
26704         return current;
26705       }
26706
26707
26708       function updateOptions() {
26709
26710         var previousValue = options && selectCtrl.readValue();
26711
26712         options = ngOptions.getOptions();
26713
26714         var groupMap = {};
26715         var currentElement = selectElement[0].firstChild;
26716
26717         // Ensure that the empty option is always there if it was explicitly provided
26718         if (providedEmptyOption) {
26719           selectElement.prepend(emptyOption);
26720         }
26721
26722         currentElement = skipEmptyAndUnknownOptions(currentElement);
26723
26724         options.items.forEach(function updateOption(option) {
26725           var group;
26726           var groupElement;
26727           var optionElement;
26728
26729           if (option.group) {
26730
26731             // This option is to live in a group
26732             // See if we have already created this group
26733             group = groupMap[option.group];
26734
26735             if (!group) {
26736
26737               // We have not already created this group
26738               groupElement = addOrReuseElement(selectElement[0],
26739                                                currentElement,
26740                                                'optgroup',
26741                                                optGroupTemplate);
26742               // Move to the next element
26743               currentElement = groupElement.nextSibling;
26744
26745               // Update the label on the group element
26746               groupElement.label = option.group;
26747
26748               // Store it for use later
26749               group = groupMap[option.group] = {
26750                 groupElement: groupElement,
26751                 currentOptionElement: groupElement.firstChild
26752               };
26753
26754             }
26755
26756             // So now we have a group for this option we add the option to the group
26757             optionElement = addOrReuseElement(group.groupElement,
26758                                               group.currentOptionElement,
26759                                               'option',
26760                                               optionTemplate);
26761             updateOptionElement(option, optionElement);
26762             // Move to the next element
26763             group.currentOptionElement = optionElement.nextSibling;
26764
26765           } else {
26766
26767             // This option is not in a group
26768             optionElement = addOrReuseElement(selectElement[0],
26769                                               currentElement,
26770                                               'option',
26771                                               optionTemplate);
26772             updateOptionElement(option, optionElement);
26773             // Move to the next element
26774             currentElement = optionElement.nextSibling;
26775           }
26776         });
26777
26778
26779         // Now remove all excess options and group
26780         Object.keys(groupMap).forEach(function(key) {
26781           removeExcessElements(groupMap[key].currentOptionElement);
26782         });
26783         removeExcessElements(currentElement);
26784
26785         ngModelCtrl.$render();
26786
26787         // Check to see if the value has changed due to the update to the options
26788         if (!ngModelCtrl.$isEmpty(previousValue)) {
26789           var nextValue = selectCtrl.readValue();
26790           if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
26791             ngModelCtrl.$setViewValue(nextValue);
26792             ngModelCtrl.$render();
26793           }
26794         }
26795
26796       }
26797   }
26798
26799   return {
26800     restrict: 'A',
26801     terminal: true,
26802     require: ['select', '?ngModel'],
26803     link: {
26804       pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26805         // Deactivate the SelectController.register method to prevent
26806         // option directives from accidentally registering themselves
26807         // (and unwanted $destroy handlers etc.)
26808         ctrls[0].registerOption = noop;
26809       },
26810       post: ngOptionsPostLink
26811     }
26812   };
26813 }];
26814
26815 /**
26816  * @ngdoc directive
26817  * @name ngPluralize
26818  * @restrict EA
26819  *
26820  * @description
26821  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
26822  * These rules are bundled with angular.js, but can be overridden
26823  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
26824  * by specifying the mappings between
26825  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26826  * and the strings to be displayed.
26827  *
26828  * # Plural categories and explicit number rules
26829  * There are two
26830  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26831  * in Angular's default en-US locale: "one" and "other".
26832  *
26833  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
26834  * any number that is not 1), an explicit number rule can only match one number. For example, the
26835  * explicit number rule for "3" matches the number 3. There are examples of plural categories
26836  * and explicit number rules throughout the rest of this documentation.
26837  *
26838  * # Configuring ngPluralize
26839  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
26840  * You can also provide an optional attribute, `offset`.
26841  *
26842  * The value of the `count` attribute can be either a string or an {@link guide/expression
26843  * Angular expression}; these are evaluated on the current scope for its bound value.
26844  *
26845  * The `when` attribute specifies the mappings between plural categories and the actual
26846  * string to be displayed. The value of the attribute should be a JSON object.
26847  *
26848  * The following example shows how to configure ngPluralize:
26849  *
26850  * ```html
26851  * <ng-pluralize count="personCount"
26852                  when="{'0': 'Nobody is viewing.',
26853  *                      'one': '1 person is viewing.',
26854  *                      'other': '{} people are viewing.'}">
26855  * </ng-pluralize>
26856  *```
26857  *
26858  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
26859  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
26860  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
26861  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
26862  * show "a dozen people are viewing".
26863  *
26864  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
26865  * into pluralized strings. In the previous example, Angular will replace `{}` with
26866  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
26867  * for <span ng-non-bindable>{{numberExpression}}</span>.
26868  *
26869  * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
26870  * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
26871  *
26872  * # Configuring ngPluralize with offset
26873  * The `offset` attribute allows further customization of pluralized text, which can result in
26874  * a better user experience. For example, instead of the message "4 people are viewing this document",
26875  * you might display "John, Kate and 2 others are viewing this document".
26876  * The offset attribute allows you to offset a number by any desired value.
26877  * Let's take a look at an example:
26878  *
26879  * ```html
26880  * <ng-pluralize count="personCount" offset=2
26881  *               when="{'0': 'Nobody is viewing.',
26882  *                      '1': '{{person1}} is viewing.',
26883  *                      '2': '{{person1}} and {{person2}} are viewing.',
26884  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
26885  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26886  * </ng-pluralize>
26887  * ```
26888  *
26889  * Notice that we are still using two plural categories(one, other), but we added
26890  * three explicit number rules 0, 1 and 2.
26891  * When one person, perhaps John, views the document, "John is viewing" will be shown.
26892  * When three people view the document, no explicit number rule is found, so
26893  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
26894  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
26895  * is shown.
26896  *
26897  * Note that when you specify offsets, you must provide explicit number rules for
26898  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
26899  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
26900  * plural categories "one" and "other".
26901  *
26902  * @param {string|expression} count The variable to be bound to.
26903  * @param {string} when The mapping between plural category to its corresponding strings.
26904  * @param {number=} offset Offset to deduct from the total number.
26905  *
26906  * @example
26907     <example module="pluralizeExample">
26908       <file name="index.html">
26909         <script>
26910           angular.module('pluralizeExample', [])
26911             .controller('ExampleController', ['$scope', function($scope) {
26912               $scope.person1 = 'Igor';
26913               $scope.person2 = 'Misko';
26914               $scope.personCount = 1;
26915             }]);
26916         </script>
26917         <div ng-controller="ExampleController">
26918           <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
26919           <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
26920           <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
26921
26922           <!--- Example with simple pluralization rules for en locale --->
26923           Without Offset:
26924           <ng-pluralize count="personCount"
26925                         when="{'0': 'Nobody is viewing.',
26926                                'one': '1 person is viewing.',
26927                                'other': '{} people are viewing.'}">
26928           </ng-pluralize><br>
26929
26930           <!--- Example with offset --->
26931           With Offset(2):
26932           <ng-pluralize count="personCount" offset=2
26933                         when="{'0': 'Nobody is viewing.',
26934                                '1': '{{person1}} is viewing.',
26935                                '2': '{{person1}} and {{person2}} are viewing.',
26936                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
26937                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26938           </ng-pluralize>
26939         </div>
26940       </file>
26941       <file name="protractor.js" type="protractor">
26942         it('should show correct pluralized string', function() {
26943           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
26944           var withOffset = element.all(by.css('ng-pluralize')).get(1);
26945           var countInput = element(by.model('personCount'));
26946
26947           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
26948           expect(withOffset.getText()).toEqual('Igor is viewing.');
26949
26950           countInput.clear();
26951           countInput.sendKeys('0');
26952
26953           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
26954           expect(withOffset.getText()).toEqual('Nobody is viewing.');
26955
26956           countInput.clear();
26957           countInput.sendKeys('2');
26958
26959           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
26960           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
26961
26962           countInput.clear();
26963           countInput.sendKeys('3');
26964
26965           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
26966           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
26967
26968           countInput.clear();
26969           countInput.sendKeys('4');
26970
26971           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
26972           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
26973         });
26974         it('should show data-bound names', function() {
26975           var withOffset = element.all(by.css('ng-pluralize')).get(1);
26976           var personCount = element(by.model('personCount'));
26977           var person1 = element(by.model('person1'));
26978           var person2 = element(by.model('person2'));
26979           personCount.clear();
26980           personCount.sendKeys('4');
26981           person1.clear();
26982           person1.sendKeys('Di');
26983           person2.clear();
26984           person2.sendKeys('Vojta');
26985           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
26986         });
26987       </file>
26988     </example>
26989  */
26990 var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
26991   var BRACE = /{}/g,
26992       IS_WHEN = /^when(Minus)?(.+)$/;
26993
26994   return {
26995     link: function(scope, element, attr) {
26996       var numberExp = attr.count,
26997           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
26998           offset = attr.offset || 0,
26999           whens = scope.$eval(whenExp) || {},
27000           whensExpFns = {},
27001           startSymbol = $interpolate.startSymbol(),
27002           endSymbol = $interpolate.endSymbol(),
27003           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
27004           watchRemover = angular.noop,
27005           lastCount;
27006
27007       forEach(attr, function(expression, attributeName) {
27008         var tmpMatch = IS_WHEN.exec(attributeName);
27009         if (tmpMatch) {
27010           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
27011           whens[whenKey] = element.attr(attr.$attr[attributeName]);
27012         }
27013       });
27014       forEach(whens, function(expression, key) {
27015         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
27016
27017       });
27018
27019       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
27020         var count = parseFloat(newVal);
27021         var countIsNaN = isNaN(count);
27022
27023         if (!countIsNaN && !(count in whens)) {
27024           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
27025           // Otherwise, check it against pluralization rules in $locale service.
27026           count = $locale.pluralCat(count - offset);
27027         }
27028
27029         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
27030         // In JS `NaN !== NaN`, so we have to exlicitly check.
27031         if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
27032           watchRemover();
27033           var whenExpFn = whensExpFns[count];
27034           if (isUndefined(whenExpFn)) {
27035             if (newVal != null) {
27036               $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
27037             }
27038             watchRemover = noop;
27039             updateElementText();
27040           } else {
27041             watchRemover = scope.$watch(whenExpFn, updateElementText);
27042           }
27043           lastCount = count;
27044         }
27045       });
27046
27047       function updateElementText(newText) {
27048         element.text(newText || '');
27049       }
27050     }
27051   };
27052 }];
27053
27054 /**
27055  * @ngdoc directive
27056  * @name ngRepeat
27057  * @multiElement
27058  *
27059  * @description
27060  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
27061  * instance gets its own scope, where the given loop variable is set to the current collection item,
27062  * and `$index` is set to the item index or key.
27063  *
27064  * Special properties are exposed on the local scope of each template instance, including:
27065  *
27066  * | Variable  | Type            | Details                                                                     |
27067  * |-----------|-----------------|-----------------------------------------------------------------------------|
27068  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
27069  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
27070  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
27071  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
27072  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
27073  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
27074  *
27075  * <div class="alert alert-info">
27076  *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
27077  *   This may be useful when, for instance, nesting ngRepeats.
27078  * </div>
27079  *
27080  *
27081  * # Iterating over object properties
27082  *
27083  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
27084  * syntax:
27085  *
27086  * ```js
27087  * <div ng-repeat="(key, value) in myObj"> ... </div>
27088  * ```
27089  *
27090  * You need to be aware that the JavaScript specification does not define the order of keys
27091  * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
27092  * used to sort the keys alphabetically.)
27093  *
27094  * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
27095  * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
27096  * keys in the order in which they were defined, although there are exceptions when keys are deleted
27097  * and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
27098  *
27099  * If this is not desired, the recommended workaround is to convert your object into an array
27100  * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
27101  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
27102  * or implement a `$watch` on the object yourself.
27103  *
27104  *
27105  * # Tracking and Duplicates
27106  *
27107  * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
27108  * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
27109  *
27110  * * When an item is added, a new instance of the template is added to the DOM.
27111  * * When an item is removed, its template instance is removed from the DOM.
27112  * * When items are reordered, their respective templates are reordered in the DOM.
27113  *
27114  * To minimize creation of DOM elements, `ngRepeat` uses a function
27115  * to "keep track" of all items in the collection and their corresponding DOM elements.
27116  * For example, if an item is added to the collection, ngRepeat will know that all other items
27117  * already have DOM elements, and will not re-render them.
27118  *
27119  * The default tracking function (which tracks items by their identity) does not allow
27120  * duplicate items in arrays. This is because when there are duplicates, it is not possible
27121  * to maintain a one-to-one mapping between collection items and DOM elements.
27122  *
27123  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
27124  * with your own using the `track by` expression.
27125  *
27126  * For example, you may track items by the index of each item in the collection, using the
27127  * special scope property `$index`:
27128  * ```html
27129  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
27130  *      {{n}}
27131  *    </div>
27132  * ```
27133  *
27134  * You may also use arbitrary expressions in `track by`, including references to custom functions
27135  * on the scope:
27136  * ```html
27137  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
27138  *      {{n}}
27139  *    </div>
27140  * ```
27141  *
27142  * <div class="alert alert-success">
27143  * If you are working with objects that have an identifier property, you should track
27144  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27145  * will not have to rebuild the DOM elements for items it has already rendered, even if the
27146  * JavaScript objects in the collection have been substituted for new ones. For large collections,
27147  * this signifincantly improves rendering performance. If you don't have a unique identifier,
27148  * `track by $index` can also provide a performance boost.
27149  * </div>
27150  * ```html
27151  *    <div ng-repeat="model in collection track by model.id">
27152  *      {{model.name}}
27153  *    </div>
27154  * ```
27155  *
27156  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
27157  * `$id` function, which tracks items by their identity:
27158  * ```html
27159  *    <div ng-repeat="obj in collection track by $id(obj)">
27160  *      {{obj.prop}}
27161  *    </div>
27162  * ```
27163  *
27164  * <div class="alert alert-warning">
27165  * **Note:** `track by` must always be the last expression:
27166  * </div>
27167  * ```
27168  * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
27169  *     {{model.name}}
27170  * </div>
27171  * ```
27172  *
27173  * # Special repeat start and end points
27174  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
27175  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
27176  * 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)
27177  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
27178  *
27179  * The example below makes use of this feature:
27180  * ```html
27181  *   <header ng-repeat-start="item in items">
27182  *     Header {{ item }}
27183  *   </header>
27184  *   <div class="body">
27185  *     Body {{ item }}
27186  *   </div>
27187  *   <footer ng-repeat-end>
27188  *     Footer {{ item }}
27189  *   </footer>
27190  * ```
27191  *
27192  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
27193  * ```html
27194  *   <header>
27195  *     Header A
27196  *   </header>
27197  *   <div class="body">
27198  *     Body A
27199  *   </div>
27200  *   <footer>
27201  *     Footer A
27202  *   </footer>
27203  *   <header>
27204  *     Header B
27205  *   </header>
27206  *   <div class="body">
27207  *     Body B
27208  *   </div>
27209  *   <footer>
27210  *     Footer B
27211  *   </footer>
27212  * ```
27213  *
27214  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
27215  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
27216  *
27217  * @animations
27218  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
27219  *
27220  * **.leave** - when an item is removed from the list or when an item is filtered out
27221  *
27222  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
27223  *
27224  * @element ANY
27225  * @scope
27226  * @priority 1000
27227  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
27228  *   formats are currently supported:
27229  *
27230  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
27231  *     is a scope expression giving the collection to enumerate.
27232  *
27233  *     For example: `album in artist.albums`.
27234  *
27235  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
27236  *     and `expression` is the scope expression giving the collection to enumerate.
27237  *
27238  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
27239  *
27240  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
27241  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
27242  *     is specified, ng-repeat associates elements by identity. It is an error to have
27243  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
27244  *     mapped to the same DOM element, which is not possible.)
27245  *
27246  *     Note that the tracking expression must come last, after any filters, and the alias expression.
27247  *
27248  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
27249  *     will be associated by item identity in the array.
27250  *
27251  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
27252  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
27253  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
27254  *     element in the same way in the DOM.
27255  *
27256  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
27257  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
27258  *     property is same.
27259  *
27260  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
27261  *     to items in conjunction with a tracking expression.
27262  *
27263  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
27264  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
27265  *     when a filter is active on the repeater, but the filtered result set is empty.
27266  *
27267  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
27268  *     the items have been processed through the filter.
27269  *
27270  *     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
27271  *     (and not as operator, inside an expression).
27272  *
27273  *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
27274  *
27275  * @example
27276  * This example initializes the scope to a list of names and
27277  * then uses `ngRepeat` to display every person:
27278   <example module="ngAnimate" deps="angular-animate.js" animations="true">
27279     <file name="index.html">
27280       <div ng-init="friends = [
27281         {name:'John', age:25, gender:'boy'},
27282         {name:'Jessie', age:30, gender:'girl'},
27283         {name:'Johanna', age:28, gender:'girl'},
27284         {name:'Joy', age:15, gender:'girl'},
27285         {name:'Mary', age:28, gender:'girl'},
27286         {name:'Peter', age:95, gender:'boy'},
27287         {name:'Sebastian', age:50, gender:'boy'},
27288         {name:'Erika', age:27, gender:'girl'},
27289         {name:'Patrick', age:40, gender:'boy'},
27290         {name:'Samantha', age:60, gender:'girl'}
27291       ]">
27292         I have {{friends.length}} friends. They are:
27293         <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
27294         <ul class="example-animate-container">
27295           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
27296             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
27297           </li>
27298           <li class="animate-repeat" ng-if="results.length == 0">
27299             <strong>No results found...</strong>
27300           </li>
27301         </ul>
27302       </div>
27303     </file>
27304     <file name="animations.css">
27305       .example-animate-container {
27306         background:white;
27307         border:1px solid black;
27308         list-style:none;
27309         margin:0;
27310         padding:0 10px;
27311       }
27312
27313       .animate-repeat {
27314         line-height:40px;
27315         list-style:none;
27316         box-sizing:border-box;
27317       }
27318
27319       .animate-repeat.ng-move,
27320       .animate-repeat.ng-enter,
27321       .animate-repeat.ng-leave {
27322         transition:all linear 0.5s;
27323       }
27324
27325       .animate-repeat.ng-leave.ng-leave-active,
27326       .animate-repeat.ng-move,
27327       .animate-repeat.ng-enter {
27328         opacity:0;
27329         max-height:0;
27330       }
27331
27332       .animate-repeat.ng-leave,
27333       .animate-repeat.ng-move.ng-move-active,
27334       .animate-repeat.ng-enter.ng-enter-active {
27335         opacity:1;
27336         max-height:40px;
27337       }
27338     </file>
27339     <file name="protractor.js" type="protractor">
27340       var friends = element.all(by.repeater('friend in friends'));
27341
27342       it('should render initial data set', function() {
27343         expect(friends.count()).toBe(10);
27344         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
27345         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
27346         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
27347         expect(element(by.binding('friends.length')).getText())
27348             .toMatch("I have 10 friends. They are:");
27349       });
27350
27351        it('should update repeater when filter predicate changes', function() {
27352          expect(friends.count()).toBe(10);
27353
27354          element(by.model('q')).sendKeys('ma');
27355
27356          expect(friends.count()).toBe(2);
27357          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
27358          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
27359        });
27360       </file>
27361     </example>
27362  */
27363 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
27364   var NG_REMOVED = '$$NG_REMOVED';
27365   var ngRepeatMinErr = minErr('ngRepeat');
27366
27367   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
27368     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
27369     scope[valueIdentifier] = value;
27370     if (keyIdentifier) scope[keyIdentifier] = key;
27371     scope.$index = index;
27372     scope.$first = (index === 0);
27373     scope.$last = (index === (arrayLength - 1));
27374     scope.$middle = !(scope.$first || scope.$last);
27375     // jshint bitwise: false
27376     scope.$odd = !(scope.$even = (index&1) === 0);
27377     // jshint bitwise: true
27378   };
27379
27380   var getBlockStart = function(block) {
27381     return block.clone[0];
27382   };
27383
27384   var getBlockEnd = function(block) {
27385     return block.clone[block.clone.length - 1];
27386   };
27387
27388
27389   return {
27390     restrict: 'A',
27391     multiElement: true,
27392     transclude: 'element',
27393     priority: 1000,
27394     terminal: true,
27395     $$tlb: true,
27396     compile: function ngRepeatCompile($element, $attr) {
27397       var expression = $attr.ngRepeat;
27398       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
27399
27400       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*$/);
27401
27402       if (!match) {
27403         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
27404             expression);
27405       }
27406
27407       var lhs = match[1];
27408       var rhs = match[2];
27409       var aliasAs = match[3];
27410       var trackByExp = match[4];
27411
27412       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
27413
27414       if (!match) {
27415         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
27416             lhs);
27417       }
27418       var valueIdentifier = match[3] || match[1];
27419       var keyIdentifier = match[2];
27420
27421       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
27422           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
27423         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
27424           aliasAs);
27425       }
27426
27427       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
27428       var hashFnLocals = {$id: hashKey};
27429
27430       if (trackByExp) {
27431         trackByExpGetter = $parse(trackByExp);
27432       } else {
27433         trackByIdArrayFn = function(key, value) {
27434           return hashKey(value);
27435         };
27436         trackByIdObjFn = function(key) {
27437           return key;
27438         };
27439       }
27440
27441       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
27442
27443         if (trackByExpGetter) {
27444           trackByIdExpFn = function(key, value, index) {
27445             // assign key, value, and $index to the locals so that they can be used in hash functions
27446             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
27447             hashFnLocals[valueIdentifier] = value;
27448             hashFnLocals.$index = index;
27449             return trackByExpGetter($scope, hashFnLocals);
27450           };
27451         }
27452
27453         // Store a list of elements from previous run. This is a hash where key is the item from the
27454         // iterator, and the value is objects with following properties.
27455         //   - scope: bound scope
27456         //   - element: previous element.
27457         //   - index: position
27458         //
27459         // We are using no-proto object so that we don't need to guard against inherited props via
27460         // hasOwnProperty.
27461         var lastBlockMap = createMap();
27462
27463         //watch props
27464         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
27465           var index, length,
27466               previousNode = $element[0],     // node that cloned nodes should be inserted after
27467                                               // initialized to the comment node anchor
27468               nextNode,
27469               // Same as lastBlockMap but it has the current state. It will become the
27470               // lastBlockMap on the next iteration.
27471               nextBlockMap = createMap(),
27472               collectionLength,
27473               key, value, // key/value of iteration
27474               trackById,
27475               trackByIdFn,
27476               collectionKeys,
27477               block,       // last object information {scope, element, id}
27478               nextBlockOrder,
27479               elementsToRemove;
27480
27481           if (aliasAs) {
27482             $scope[aliasAs] = collection;
27483           }
27484
27485           if (isArrayLike(collection)) {
27486             collectionKeys = collection;
27487             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
27488           } else {
27489             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
27490             // if object, extract keys, in enumeration order, unsorted
27491             collectionKeys = [];
27492             for (var itemKey in collection) {
27493               if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
27494                 collectionKeys.push(itemKey);
27495               }
27496             }
27497           }
27498
27499           collectionLength = collectionKeys.length;
27500           nextBlockOrder = new Array(collectionLength);
27501
27502           // locate existing items
27503           for (index = 0; index < collectionLength; index++) {
27504             key = (collection === collectionKeys) ? index : collectionKeys[index];
27505             value = collection[key];
27506             trackById = trackByIdFn(key, value, index);
27507             if (lastBlockMap[trackById]) {
27508               // found previously seen block
27509               block = lastBlockMap[trackById];
27510               delete lastBlockMap[trackById];
27511               nextBlockMap[trackById] = block;
27512               nextBlockOrder[index] = block;
27513             } else if (nextBlockMap[trackById]) {
27514               // if collision detected. restore lastBlockMap and throw an error
27515               forEach(nextBlockOrder, function(block) {
27516                 if (block && block.scope) lastBlockMap[block.id] = block;
27517               });
27518               throw ngRepeatMinErr('dupes',
27519                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
27520                   expression, trackById, value);
27521             } else {
27522               // new never before seen block
27523               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
27524               nextBlockMap[trackById] = true;
27525             }
27526           }
27527
27528           // remove leftover items
27529           for (var blockKey in lastBlockMap) {
27530             block = lastBlockMap[blockKey];
27531             elementsToRemove = getBlockNodes(block.clone);
27532             $animate.leave(elementsToRemove);
27533             if (elementsToRemove[0].parentNode) {
27534               // if the element was not removed yet because of pending animation, mark it as deleted
27535               // so that we can ignore it later
27536               for (index = 0, length = elementsToRemove.length; index < length; index++) {
27537                 elementsToRemove[index][NG_REMOVED] = true;
27538               }
27539             }
27540             block.scope.$destroy();
27541           }
27542
27543           // we are not using forEach for perf reasons (trying to avoid #call)
27544           for (index = 0; index < collectionLength; index++) {
27545             key = (collection === collectionKeys) ? index : collectionKeys[index];
27546             value = collection[key];
27547             block = nextBlockOrder[index];
27548
27549             if (block.scope) {
27550               // if we have already seen this object, then we need to reuse the
27551               // associated scope/element
27552
27553               nextNode = previousNode;
27554
27555               // skip nodes that are already pending removal via leave animation
27556               do {
27557                 nextNode = nextNode.nextSibling;
27558               } while (nextNode && nextNode[NG_REMOVED]);
27559
27560               if (getBlockStart(block) != nextNode) {
27561                 // existing item which got moved
27562                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
27563               }
27564               previousNode = getBlockEnd(block);
27565               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27566             } else {
27567               // new item which we don't know about
27568               $transclude(function ngRepeatTransclude(clone, scope) {
27569                 block.scope = scope;
27570                 // http://jsperf.com/clone-vs-createcomment
27571                 var endNode = ngRepeatEndComment.cloneNode(false);
27572                 clone[clone.length++] = endNode;
27573
27574                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
27575                 $animate.enter(clone, null, jqLite(previousNode));
27576                 previousNode = endNode;
27577                 // Note: We only need the first/last node of the cloned nodes.
27578                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27579                 // by a directive with templateUrl when its template arrives.
27580                 block.clone = clone;
27581                 nextBlockMap[block.id] = block;
27582                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27583               });
27584             }
27585           }
27586           lastBlockMap = nextBlockMap;
27587         });
27588       };
27589     }
27590   };
27591 }];
27592
27593 var NG_HIDE_CLASS = 'ng-hide';
27594 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
27595 /**
27596  * @ngdoc directive
27597  * @name ngShow
27598  * @multiElement
27599  *
27600  * @description
27601  * The `ngShow` directive shows or hides the given HTML element based on the expression
27602  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
27603  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27604  * in AngularJS and sets the display style to none (using an !important flag).
27605  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27606  *
27607  * ```html
27608  * <!-- when $scope.myValue is truthy (element is visible) -->
27609  * <div ng-show="myValue"></div>
27610  *
27611  * <!-- when $scope.myValue is falsy (element is hidden) -->
27612  * <div ng-show="myValue" class="ng-hide"></div>
27613  * ```
27614  *
27615  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
27616  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
27617  * from the element causing the element not to appear hidden.
27618  *
27619  * ## Why is !important used?
27620  *
27621  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27622  * can be easily overridden by heavier selectors. For example, something as simple
27623  * as changing the display style on a HTML list item would make hidden elements appear visible.
27624  * This also becomes a bigger issue when dealing with CSS frameworks.
27625  *
27626  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27627  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27628  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27629  *
27630  * ### Overriding `.ng-hide`
27631  *
27632  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27633  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27634  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
27635  * with extra animation classes that can be added.
27636  *
27637  * ```css
27638  * .ng-hide:not(.ng-hide-animate) {
27639  *   /&#42; this is just another form of hiding an element &#42;/
27640  *   display: block!important;
27641  *   position: absolute;
27642  *   top: -9999px;
27643  *   left: -9999px;
27644  * }
27645  * ```
27646  *
27647  * By default you don't need to override in CSS anything and the animations will work around the display style.
27648  *
27649  * ## A note about animations with `ngShow`
27650  *
27651  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27652  * is true and false. This system works like the animation system present with ngClass except that
27653  * you must also include the !important flag to override the display property
27654  * so that you can perform an animation when the element is hidden during the time of the animation.
27655  *
27656  * ```css
27657  * //
27658  * //a working example can be found at the bottom of this page
27659  * //
27660  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27661  *   /&#42; this is required as of 1.3x to properly
27662  *      apply all styling in a show/hide animation &#42;/
27663  *   transition: 0s linear all;
27664  * }
27665  *
27666  * .my-element.ng-hide-add-active,
27667  * .my-element.ng-hide-remove-active {
27668  *   /&#42; the transition is defined in the active class &#42;/
27669  *   transition: 1s linear all;
27670  * }
27671  *
27672  * .my-element.ng-hide-add { ... }
27673  * .my-element.ng-hide-add.ng-hide-add-active { ... }
27674  * .my-element.ng-hide-remove { ... }
27675  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27676  * ```
27677  *
27678  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27679  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27680  *
27681  * @animations
27682  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
27683  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
27684  *
27685  * @element ANY
27686  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
27687  *     then the element is shown or hidden respectively.
27688  *
27689  * @example
27690   <example module="ngAnimate" deps="angular-animate.js" animations="true">
27691     <file name="index.html">
27692       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
27693       <div>
27694         Show:
27695         <div class="check-element animate-show" ng-show="checked">
27696           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27697         </div>
27698       </div>
27699       <div>
27700         Hide:
27701         <div class="check-element animate-show" ng-hide="checked">
27702           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27703         </div>
27704       </div>
27705     </file>
27706     <file name="glyphicons.css">
27707       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27708     </file>
27709     <file name="animations.css">
27710       .animate-show {
27711         line-height: 20px;
27712         opacity: 1;
27713         padding: 10px;
27714         border: 1px solid black;
27715         background: white;
27716       }
27717
27718       .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
27719         transition: all linear 0.5s;
27720       }
27721
27722       .animate-show.ng-hide {
27723         line-height: 0;
27724         opacity: 0;
27725         padding: 0 10px;
27726       }
27727
27728       .check-element {
27729         padding: 10px;
27730         border: 1px solid black;
27731         background: white;
27732       }
27733     </file>
27734     <file name="protractor.js" type="protractor">
27735       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27736       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27737
27738       it('should check ng-show / ng-hide', function() {
27739         expect(thumbsUp.isDisplayed()).toBeFalsy();
27740         expect(thumbsDown.isDisplayed()).toBeTruthy();
27741
27742         element(by.model('checked')).click();
27743
27744         expect(thumbsUp.isDisplayed()).toBeTruthy();
27745         expect(thumbsDown.isDisplayed()).toBeFalsy();
27746       });
27747     </file>
27748   </example>
27749  */
27750 var ngShowDirective = ['$animate', function($animate) {
27751   return {
27752     restrict: 'A',
27753     multiElement: true,
27754     link: function(scope, element, attr) {
27755       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
27756         // we're adding a temporary, animation-specific class for ng-hide since this way
27757         // we can control when the element is actually displayed on screen without having
27758         // to have a global/greedy CSS selector that breaks when other animations are run.
27759         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
27760         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
27761           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27762         });
27763       });
27764     }
27765   };
27766 }];
27767
27768
27769 /**
27770  * @ngdoc directive
27771  * @name ngHide
27772  * @multiElement
27773  *
27774  * @description
27775  * The `ngHide` directive shows or hides the given HTML element based on the expression
27776  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
27777  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27778  * in AngularJS and sets the display style to none (using an !important flag).
27779  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27780  *
27781  * ```html
27782  * <!-- when $scope.myValue is truthy (element is hidden) -->
27783  * <div ng-hide="myValue" class="ng-hide"></div>
27784  *
27785  * <!-- when $scope.myValue is falsy (element is visible) -->
27786  * <div ng-hide="myValue"></div>
27787  * ```
27788  *
27789  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
27790  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
27791  * from the element causing the element not to appear hidden.
27792  *
27793  * ## Why is !important used?
27794  *
27795  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27796  * can be easily overridden by heavier selectors. For example, something as simple
27797  * as changing the display style on a HTML list item would make hidden elements appear visible.
27798  * This also becomes a bigger issue when dealing with CSS frameworks.
27799  *
27800  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27801  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27802  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27803  *
27804  * ### Overriding `.ng-hide`
27805  *
27806  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27807  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27808  * class in CSS:
27809  *
27810  * ```css
27811  * .ng-hide {
27812  *   /&#42; this is just another form of hiding an element &#42;/
27813  *   display: block!important;
27814  *   position: absolute;
27815  *   top: -9999px;
27816  *   left: -9999px;
27817  * }
27818  * ```
27819  *
27820  * By default you don't need to override in CSS anything and the animations will work around the display style.
27821  *
27822  * ## A note about animations with `ngHide`
27823  *
27824  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27825  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
27826  * CSS class is added and removed for you instead of your own CSS class.
27827  *
27828  * ```css
27829  * //
27830  * //a working example can be found at the bottom of this page
27831  * //
27832  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27833  *   transition: 0.5s linear all;
27834  * }
27835  *
27836  * .my-element.ng-hide-add { ... }
27837  * .my-element.ng-hide-add.ng-hide-add-active { ... }
27838  * .my-element.ng-hide-remove { ... }
27839  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27840  * ```
27841  *
27842  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27843  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27844  *
27845  * @animations
27846  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
27847  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
27848  *
27849  * @element ANY
27850  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
27851  *     the element is shown or hidden respectively.
27852  *
27853  * @example
27854   <example module="ngAnimate" deps="angular-animate.js" animations="true">
27855     <file name="index.html">
27856       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
27857       <div>
27858         Show:
27859         <div class="check-element animate-hide" ng-show="checked">
27860           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27861         </div>
27862       </div>
27863       <div>
27864         Hide:
27865         <div class="check-element animate-hide" ng-hide="checked">
27866           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27867         </div>
27868       </div>
27869     </file>
27870     <file name="glyphicons.css">
27871       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27872     </file>
27873     <file name="animations.css">
27874       .animate-hide {
27875         transition: all linear 0.5s;
27876         line-height: 20px;
27877         opacity: 1;
27878         padding: 10px;
27879         border: 1px solid black;
27880         background: white;
27881       }
27882
27883       .animate-hide.ng-hide {
27884         line-height: 0;
27885         opacity: 0;
27886         padding: 0 10px;
27887       }
27888
27889       .check-element {
27890         padding: 10px;
27891         border: 1px solid black;
27892         background: white;
27893       }
27894     </file>
27895     <file name="protractor.js" type="protractor">
27896       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27897       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27898
27899       it('should check ng-show / ng-hide', function() {
27900         expect(thumbsUp.isDisplayed()).toBeFalsy();
27901         expect(thumbsDown.isDisplayed()).toBeTruthy();
27902
27903         element(by.model('checked')).click();
27904
27905         expect(thumbsUp.isDisplayed()).toBeTruthy();
27906         expect(thumbsDown.isDisplayed()).toBeFalsy();
27907       });
27908     </file>
27909   </example>
27910  */
27911 var ngHideDirective = ['$animate', function($animate) {
27912   return {
27913     restrict: 'A',
27914     multiElement: true,
27915     link: function(scope, element, attr) {
27916       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
27917         // The comment inside of the ngShowDirective explains why we add and
27918         // remove a temporary class for the show/hide animation
27919         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
27920           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27921         });
27922       });
27923     }
27924   };
27925 }];
27926
27927 /**
27928  * @ngdoc directive
27929  * @name ngStyle
27930  * @restrict AC
27931  *
27932  * @description
27933  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
27934  *
27935  * @element ANY
27936  * @param {expression} ngStyle
27937  *
27938  * {@link guide/expression Expression} which evals to an
27939  * object whose keys are CSS style names and values are corresponding values for those CSS
27940  * keys.
27941  *
27942  * Since some CSS style names are not valid keys for an object, they must be quoted.
27943  * See the 'background-color' style in the example below.
27944  *
27945  * @example
27946    <example>
27947      <file name="index.html">
27948         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
27949         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
27950         <input type="button" value="clear" ng-click="myStyle={}">
27951         <br/>
27952         <span ng-style="myStyle">Sample Text</span>
27953         <pre>myStyle={{myStyle}}</pre>
27954      </file>
27955      <file name="style.css">
27956        span {
27957          color: black;
27958        }
27959      </file>
27960      <file name="protractor.js" type="protractor">
27961        var colorSpan = element(by.css('span'));
27962
27963        it('should check ng-style', function() {
27964          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
27965          element(by.css('input[value=\'set color\']')).click();
27966          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
27967          element(by.css('input[value=clear]')).click();
27968          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
27969        });
27970      </file>
27971    </example>
27972  */
27973 var ngStyleDirective = ngDirective(function(scope, element, attr) {
27974   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
27975     if (oldStyles && (newStyles !== oldStyles)) {
27976       forEach(oldStyles, function(val, style) { element.css(style, '');});
27977     }
27978     if (newStyles) element.css(newStyles);
27979   }, true);
27980 });
27981
27982 /**
27983  * @ngdoc directive
27984  * @name ngSwitch
27985  * @restrict EA
27986  *
27987  * @description
27988  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
27989  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
27990  * as specified in the template.
27991  *
27992  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
27993  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
27994  * matches the value obtained from the evaluated expression. In other words, you define a container element
27995  * (where you place the directive), place an expression on the **`on="..."` attribute**
27996  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
27997  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
27998  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
27999  * attribute is displayed.
28000  *
28001  * <div class="alert alert-info">
28002  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
28003  * as literal string values to match against.
28004  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
28005  * value of the expression `$scope.someVal`.
28006  * </div>
28007
28008  * @animations
28009  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
28010  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
28011  *
28012  * @usage
28013  *
28014  * ```
28015  * <ANY ng-switch="expression">
28016  *   <ANY ng-switch-when="matchValue1">...</ANY>
28017  *   <ANY ng-switch-when="matchValue2">...</ANY>
28018  *   <ANY ng-switch-default>...</ANY>
28019  * </ANY>
28020  * ```
28021  *
28022  *
28023  * @scope
28024  * @priority 1200
28025  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
28026  * On child elements add:
28027  *
28028  * * `ngSwitchWhen`: the case statement to match against. If match then this
28029  *   case will be displayed. If the same match appears multiple times, all the
28030  *   elements will be displayed.
28031  * * `ngSwitchDefault`: the default case when no other case match. If there
28032  *   are multiple default cases, all of them will be displayed when no other
28033  *   case match.
28034  *
28035  *
28036  * @example
28037   <example module="switchExample" deps="angular-animate.js" animations="true">
28038     <file name="index.html">
28039       <div ng-controller="ExampleController">
28040         <select ng-model="selection" ng-options="item for item in items">
28041         </select>
28042         <code>selection={{selection}}</code>
28043         <hr/>
28044         <div class="animate-switch-container"
28045           ng-switch on="selection">
28046             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
28047             <div class="animate-switch" ng-switch-when="home">Home Span</div>
28048             <div class="animate-switch" ng-switch-default>default</div>
28049         </div>
28050       </div>
28051     </file>
28052     <file name="script.js">
28053       angular.module('switchExample', ['ngAnimate'])
28054         .controller('ExampleController', ['$scope', function($scope) {
28055           $scope.items = ['settings', 'home', 'other'];
28056           $scope.selection = $scope.items[0];
28057         }]);
28058     </file>
28059     <file name="animations.css">
28060       .animate-switch-container {
28061         position:relative;
28062         background:white;
28063         border:1px solid black;
28064         height:40px;
28065         overflow:hidden;
28066       }
28067
28068       .animate-switch {
28069         padding:10px;
28070       }
28071
28072       .animate-switch.ng-animate {
28073         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
28074
28075         position:absolute;
28076         top:0;
28077         left:0;
28078         right:0;
28079         bottom:0;
28080       }
28081
28082       .animate-switch.ng-leave.ng-leave-active,
28083       .animate-switch.ng-enter {
28084         top:-50px;
28085       }
28086       .animate-switch.ng-leave,
28087       .animate-switch.ng-enter.ng-enter-active {
28088         top:0;
28089       }
28090     </file>
28091     <file name="protractor.js" type="protractor">
28092       var switchElem = element(by.css('[ng-switch]'));
28093       var select = element(by.model('selection'));
28094
28095       it('should start in settings', function() {
28096         expect(switchElem.getText()).toMatch(/Settings Div/);
28097       });
28098       it('should change to home', function() {
28099         select.all(by.css('option')).get(1).click();
28100         expect(switchElem.getText()).toMatch(/Home Span/);
28101       });
28102       it('should select default', function() {
28103         select.all(by.css('option')).get(2).click();
28104         expect(switchElem.getText()).toMatch(/default/);
28105       });
28106     </file>
28107   </example>
28108  */
28109 var ngSwitchDirective = ['$animate', function($animate) {
28110   return {
28111     require: 'ngSwitch',
28112
28113     // asks for $scope to fool the BC controller module
28114     controller: ['$scope', function ngSwitchController() {
28115      this.cases = {};
28116     }],
28117     link: function(scope, element, attr, ngSwitchController) {
28118       var watchExpr = attr.ngSwitch || attr.on,
28119           selectedTranscludes = [],
28120           selectedElements = [],
28121           previousLeaveAnimations = [],
28122           selectedScopes = [];
28123
28124       var spliceFactory = function(array, index) {
28125           return function() { array.splice(index, 1); };
28126       };
28127
28128       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
28129         var i, ii;
28130         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
28131           $animate.cancel(previousLeaveAnimations[i]);
28132         }
28133         previousLeaveAnimations.length = 0;
28134
28135         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
28136           var selected = getBlockNodes(selectedElements[i].clone);
28137           selectedScopes[i].$destroy();
28138           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
28139           promise.then(spliceFactory(previousLeaveAnimations, i));
28140         }
28141
28142         selectedElements.length = 0;
28143         selectedScopes.length = 0;
28144
28145         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
28146           forEach(selectedTranscludes, function(selectedTransclude) {
28147             selectedTransclude.transclude(function(caseElement, selectedScope) {
28148               selectedScopes.push(selectedScope);
28149               var anchor = selectedTransclude.element;
28150               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
28151               var block = { clone: caseElement };
28152
28153               selectedElements.push(block);
28154               $animate.enter(caseElement, anchor.parent(), anchor);
28155             });
28156           });
28157         }
28158       });
28159     }
28160   };
28161 }];
28162
28163 var ngSwitchWhenDirective = ngDirective({
28164   transclude: 'element',
28165   priority: 1200,
28166   require: '^ngSwitch',
28167   multiElement: true,
28168   link: function(scope, element, attrs, ctrl, $transclude) {
28169     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
28170     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
28171   }
28172 });
28173
28174 var ngSwitchDefaultDirective = ngDirective({
28175   transclude: 'element',
28176   priority: 1200,
28177   require: '^ngSwitch',
28178   multiElement: true,
28179   link: function(scope, element, attr, ctrl, $transclude) {
28180     ctrl.cases['?'] = (ctrl.cases['?'] || []);
28181     ctrl.cases['?'].push({ transclude: $transclude, element: element });
28182    }
28183 });
28184
28185 /**
28186  * @ngdoc directive
28187  * @name ngTransclude
28188  * @restrict EAC
28189  *
28190  * @description
28191  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
28192  *
28193  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
28194  *
28195  * @element ANY
28196  *
28197  * @example
28198    <example module="transcludeExample">
28199      <file name="index.html">
28200        <script>
28201          angular.module('transcludeExample', [])
28202           .directive('pane', function(){
28203              return {
28204                restrict: 'E',
28205                transclude: true,
28206                scope: { title:'@' },
28207                template: '<div style="border: 1px solid black;">' +
28208                            '<div style="background-color: gray">{{title}}</div>' +
28209                            '<ng-transclude></ng-transclude>' +
28210                          '</div>'
28211              };
28212          })
28213          .controller('ExampleController', ['$scope', function($scope) {
28214            $scope.title = 'Lorem Ipsum';
28215            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
28216          }]);
28217        </script>
28218        <div ng-controller="ExampleController">
28219          <input ng-model="title" aria-label="title"> <br/>
28220          <textarea ng-model="text" aria-label="text"></textarea> <br/>
28221          <pane title="{{title}}">{{text}}</pane>
28222        </div>
28223      </file>
28224      <file name="protractor.js" type="protractor">
28225         it('should have transcluded', function() {
28226           var titleElement = element(by.model('title'));
28227           titleElement.clear();
28228           titleElement.sendKeys('TITLE');
28229           var textElement = element(by.model('text'));
28230           textElement.clear();
28231           textElement.sendKeys('TEXT');
28232           expect(element(by.binding('title')).getText()).toEqual('TITLE');
28233           expect(element(by.binding('text')).getText()).toEqual('TEXT');
28234         });
28235      </file>
28236    </example>
28237  *
28238  */
28239 var ngTranscludeDirective = ngDirective({
28240   restrict: 'EAC',
28241   link: function($scope, $element, $attrs, controller, $transclude) {
28242     if (!$transclude) {
28243       throw minErr('ngTransclude')('orphan',
28244        'Illegal use of ngTransclude directive in the template! ' +
28245        'No parent directive that requires a transclusion found. ' +
28246        'Element: {0}',
28247        startingTag($element));
28248     }
28249
28250     $transclude(function(clone) {
28251       $element.empty();
28252       $element.append(clone);
28253     });
28254   }
28255 });
28256
28257 /**
28258  * @ngdoc directive
28259  * @name script
28260  * @restrict E
28261  *
28262  * @description
28263  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
28264  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
28265  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
28266  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
28267  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
28268  *
28269  * @param {string} type Must be set to `'text/ng-template'`.
28270  * @param {string} id Cache name of the template.
28271  *
28272  * @example
28273   <example>
28274     <file name="index.html">
28275       <script type="text/ng-template" id="/tpl.html">
28276         Content of the template.
28277       </script>
28278
28279       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
28280       <div id="tpl-content" ng-include src="currentTpl"></div>
28281     </file>
28282     <file name="protractor.js" type="protractor">
28283       it('should load template defined inside script tag', function() {
28284         element(by.css('#tpl-link')).click();
28285         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
28286       });
28287     </file>
28288   </example>
28289  */
28290 var scriptDirective = ['$templateCache', function($templateCache) {
28291   return {
28292     restrict: 'E',
28293     terminal: true,
28294     compile: function(element, attr) {
28295       if (attr.type == 'text/ng-template') {
28296         var templateUrl = attr.id,
28297             text = element[0].text;
28298
28299         $templateCache.put(templateUrl, text);
28300       }
28301     }
28302   };
28303 }];
28304
28305 var noopNgModelController = { $setViewValue: noop, $render: noop };
28306
28307 function chromeHack(optionElement) {
28308   // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28309   // Adding an <option selected="selected"> element to a <select required="required"> should
28310   // automatically select the new element
28311   if (optionElement[0].hasAttribute('selected')) {
28312     optionElement[0].selected = true;
28313   }
28314 }
28315
28316 /**
28317  * @ngdoc type
28318  * @name  select.SelectController
28319  * @description
28320  * The controller for the `<select>` directive. This provides support for reading
28321  * and writing the selected value(s) of the control and also coordinates dynamically
28322  * added `<option>` elements, perhaps by an `ngRepeat` directive.
28323  */
28324 var SelectController =
28325         ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
28326
28327   var self = this,
28328       optionsMap = new HashMap();
28329
28330   // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
28331   self.ngModelCtrl = noopNgModelController;
28332
28333   // The "unknown" option is one that is prepended to the list if the viewValue
28334   // does not match any of the options. When it is rendered the value of the unknown
28335   // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
28336   //
28337   // We can't just jqLite('<option>') since jqLite is not smart enough
28338   // to create it in <select> and IE barfs otherwise.
28339   self.unknownOption = jqLite(document.createElement('option'));
28340   self.renderUnknownOption = function(val) {
28341     var unknownVal = '? ' + hashKey(val) + ' ?';
28342     self.unknownOption.val(unknownVal);
28343     $element.prepend(self.unknownOption);
28344     $element.val(unknownVal);
28345   };
28346
28347   $scope.$on('$destroy', function() {
28348     // disable unknown option so that we don't do work when the whole select is being destroyed
28349     self.renderUnknownOption = noop;
28350   });
28351
28352   self.removeUnknownOption = function() {
28353     if (self.unknownOption.parent()) self.unknownOption.remove();
28354   };
28355
28356
28357   // Read the value of the select control, the implementation of this changes depending
28358   // upon whether the select can have multiple values and whether ngOptions is at work.
28359   self.readValue = function readSingleValue() {
28360     self.removeUnknownOption();
28361     return $element.val();
28362   };
28363
28364
28365   // Write the value to the select control, the implementation of this changes depending
28366   // upon whether the select can have multiple values and whether ngOptions is at work.
28367   self.writeValue = function writeSingleValue(value) {
28368     if (self.hasOption(value)) {
28369       self.removeUnknownOption();
28370       $element.val(value);
28371       if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
28372     } else {
28373       if (value == null && self.emptyOption) {
28374         self.removeUnknownOption();
28375         $element.val('');
28376       } else {
28377         self.renderUnknownOption(value);
28378       }
28379     }
28380   };
28381
28382
28383   // Tell the select control that an option, with the given value, has been added
28384   self.addOption = function(value, element) {
28385     assertNotHasOwnProperty(value, '"option value"');
28386     if (value === '') {
28387       self.emptyOption = element;
28388     }
28389     var count = optionsMap.get(value) || 0;
28390     optionsMap.put(value, count + 1);
28391     self.ngModelCtrl.$render();
28392     chromeHack(element);
28393   };
28394
28395   // Tell the select control that an option, with the given value, has been removed
28396   self.removeOption = function(value) {
28397     var count = optionsMap.get(value);
28398     if (count) {
28399       if (count === 1) {
28400         optionsMap.remove(value);
28401         if (value === '') {
28402           self.emptyOption = undefined;
28403         }
28404       } else {
28405         optionsMap.put(value, count - 1);
28406       }
28407     }
28408   };
28409
28410   // Check whether the select control has an option matching the given value
28411   self.hasOption = function(value) {
28412     return !!optionsMap.get(value);
28413   };
28414
28415
28416   self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
28417
28418     if (interpolateValueFn) {
28419       // The value attribute is interpolated
28420       var oldVal;
28421       optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
28422         if (isDefined(oldVal)) {
28423           self.removeOption(oldVal);
28424         }
28425         oldVal = newVal;
28426         self.addOption(newVal, optionElement);
28427       });
28428     } else if (interpolateTextFn) {
28429       // The text content is interpolated
28430       optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
28431         optionAttrs.$set('value', newVal);
28432         if (oldVal !== newVal) {
28433           self.removeOption(oldVal);
28434         }
28435         self.addOption(newVal, optionElement);
28436       });
28437     } else {
28438       // The value attribute is static
28439       self.addOption(optionAttrs.value, optionElement);
28440     }
28441
28442     optionElement.on('$destroy', function() {
28443       self.removeOption(optionAttrs.value);
28444       self.ngModelCtrl.$render();
28445     });
28446   };
28447 }];
28448
28449 /**
28450  * @ngdoc directive
28451  * @name select
28452  * @restrict E
28453  *
28454  * @description
28455  * HTML `SELECT` element with angular data-binding.
28456  *
28457  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
28458  * between the scope and the `<select>` control (including setting default values).
28459  * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
28460  * {@link ngOptions `ngOptions`} directives.
28461  *
28462  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
28463  * to the model identified by the `ngModel` directive. With static or repeated options, this is
28464  * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
28465  * If you want dynamic value attributes, you can use interpolation inside the value attribute.
28466  *
28467  * <div class="alert alert-warning">
28468  * Note that the value of a `select` directive used without `ngOptions` is always a string.
28469  * When the model needs to be bound to a non-string value, you must either explictly convert it
28470  * using a directive (see example below) or use `ngOptions` to specify the set of options.
28471  * This is because an option element can only be bound to string values at present.
28472  * </div>
28473  *
28474  * If the viewValue of `ngModel` does not match any of the options, then the control
28475  * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
28476  *
28477  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
28478  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
28479  * option. See example below for demonstration.
28480  *
28481  * <div class="alert alert-info">
28482  * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
28483  * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
28484  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
28485  * comprehension expression, and additionally in reducing memory and increasing speed by not creating
28486  * a new scope for each repeated instance.
28487  * </div>
28488  *
28489  *
28490  * @param {string} ngModel Assignable angular expression to data-bind to.
28491  * @param {string=} name Property name of the form under which the control is published.
28492  * @param {string=} multiple Allows multiple options to be selected. The selected values will be
28493  *     bound to the model as an array.
28494  * @param {string=} required Sets `required` validation error key if the value is not entered.
28495  * @param {string=} ngRequired Adds required attribute and required validation constraint to
28496  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
28497  * when you want to data-bind to the required attribute.
28498  * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
28499  *    interaction with the select element.
28500  * @param {string=} ngOptions sets the options that the select is populated with and defines what is
28501  * set on the model on selection. See {@link ngOptions `ngOptions`}.
28502  *
28503  * @example
28504  * ### Simple `select` elements with static options
28505  *
28506  * <example name="static-select" module="staticSelect">
28507  * <file name="index.html">
28508  * <div ng-controller="ExampleController">
28509  *   <form name="myForm">
28510  *     <label for="singleSelect"> Single select: </label><br>
28511  *     <select name="singleSelect" ng-model="data.singleSelect">
28512  *       <option value="option-1">Option 1</option>
28513  *       <option value="option-2">Option 2</option>
28514  *     </select><br>
28515  *
28516  *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
28517  *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
28518  *       <option value="">---Please select---</option> <!-- not selected / blank option -->
28519  *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
28520  *       <option value="option-2">Option 2</option>
28521  *     </select><br>
28522  *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
28523  *     <tt>singleSelect = {{data.singleSelect}}</tt>
28524  *
28525  *     <hr>
28526  *     <label for="multipleSelect"> Multiple select: </label><br>
28527  *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
28528  *       <option value="option-1">Option 1</option>
28529  *       <option value="option-2">Option 2</option>
28530  *       <option value="option-3">Option 3</option>
28531  *     </select><br>
28532  *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
28533  *   </form>
28534  * </div>
28535  * </file>
28536  * <file name="app.js">
28537  *  angular.module('staticSelect', [])
28538  *    .controller('ExampleController', ['$scope', function($scope) {
28539  *      $scope.data = {
28540  *       singleSelect: null,
28541  *       multipleSelect: [],
28542  *       option1: 'option-1',
28543  *      };
28544  *
28545  *      $scope.forceUnknownOption = function() {
28546  *        $scope.data.singleSelect = 'nonsense';
28547  *      };
28548  *   }]);
28549  * </file>
28550  *</example>
28551  *
28552  * ### Using `ngRepeat` to generate `select` options
28553  * <example name="ngrepeat-select" module="ngrepeatSelect">
28554  * <file name="index.html">
28555  * <div ng-controller="ExampleController">
28556  *   <form name="myForm">
28557  *     <label for="repeatSelect"> Repeat select: </label>
28558  *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
28559  *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
28560  *     </select>
28561  *   </form>
28562  *   <hr>
28563  *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
28564  * </div>
28565  * </file>
28566  * <file name="app.js">
28567  *  angular.module('ngrepeatSelect', [])
28568  *    .controller('ExampleController', ['$scope', function($scope) {
28569  *      $scope.data = {
28570  *       repeatSelect: null,
28571  *       availableOptions: [
28572  *         {id: '1', name: 'Option A'},
28573  *         {id: '2', name: 'Option B'},
28574  *         {id: '3', name: 'Option C'}
28575  *       ],
28576  *      };
28577  *   }]);
28578  * </file>
28579  *</example>
28580  *
28581  *
28582  * ### Using `select` with `ngOptions` and setting a default value
28583  * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
28584  *
28585  * <example name="select-with-default-values" module="defaultValueSelect">
28586  * <file name="index.html">
28587  * <div ng-controller="ExampleController">
28588  *   <form name="myForm">
28589  *     <label for="mySelect">Make a choice:</label>
28590  *     <select name="mySelect" id="mySelect"
28591  *       ng-options="option.name for option in data.availableOptions track by option.id"
28592  *       ng-model="data.selectedOption"></select>
28593  *   </form>
28594  *   <hr>
28595  *   <tt>option = {{data.selectedOption}}</tt><br/>
28596  * </div>
28597  * </file>
28598  * <file name="app.js">
28599  *  angular.module('defaultValueSelect', [])
28600  *    .controller('ExampleController', ['$scope', function($scope) {
28601  *      $scope.data = {
28602  *       availableOptions: [
28603  *         {id: '1', name: 'Option A'},
28604  *         {id: '2', name: 'Option B'},
28605  *         {id: '3', name: 'Option C'}
28606  *       ],
28607  *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
28608  *       };
28609  *   }]);
28610  * </file>
28611  *</example>
28612  *
28613  *
28614  * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
28615  *
28616  * <example name="select-with-non-string-options" module="nonStringSelect">
28617  *   <file name="index.html">
28618  *     <select ng-model="model.id" convert-to-number>
28619  *       <option value="0">Zero</option>
28620  *       <option value="1">One</option>
28621  *       <option value="2">Two</option>
28622  *     </select>
28623  *     {{ model }}
28624  *   </file>
28625  *   <file name="app.js">
28626  *     angular.module('nonStringSelect', [])
28627  *       .run(function($rootScope) {
28628  *         $rootScope.model = { id: 2 };
28629  *       })
28630  *       .directive('convertToNumber', function() {
28631  *         return {
28632  *           require: 'ngModel',
28633  *           link: function(scope, element, attrs, ngModel) {
28634  *             ngModel.$parsers.push(function(val) {
28635  *               return parseInt(val, 10);
28636  *             });
28637  *             ngModel.$formatters.push(function(val) {
28638  *               return '' + val;
28639  *             });
28640  *           }
28641  *         };
28642  *       });
28643  *   </file>
28644  *   <file name="protractor.js" type="protractor">
28645  *     it('should initialize to model', function() {
28646  *       var select = element(by.css('select'));
28647  *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
28648  *     });
28649  *   </file>
28650  * </example>
28651  *
28652  */
28653 var selectDirective = function() {
28654
28655   return {
28656     restrict: 'E',
28657     require: ['select', '?ngModel'],
28658     controller: SelectController,
28659     priority: 1,
28660     link: {
28661       pre: selectPreLink
28662     }
28663   };
28664
28665   function selectPreLink(scope, element, attr, ctrls) {
28666
28667       // if ngModel is not defined, we don't need to do anything
28668       var ngModelCtrl = ctrls[1];
28669       if (!ngModelCtrl) return;
28670
28671       var selectCtrl = ctrls[0];
28672
28673       selectCtrl.ngModelCtrl = ngModelCtrl;
28674
28675       // We delegate rendering to the `writeValue` method, which can be changed
28676       // if the select can have multiple selected values or if the options are being
28677       // generated by `ngOptions`
28678       ngModelCtrl.$render = function() {
28679         selectCtrl.writeValue(ngModelCtrl.$viewValue);
28680       };
28681
28682       // When the selected item(s) changes we delegate getting the value of the select control
28683       // to the `readValue` method, which can be changed if the select can have multiple
28684       // selected values or if the options are being generated by `ngOptions`
28685       element.on('change', function() {
28686         scope.$apply(function() {
28687           ngModelCtrl.$setViewValue(selectCtrl.readValue());
28688         });
28689       });
28690
28691       // If the select allows multiple values then we need to modify how we read and write
28692       // values from and to the control; also what it means for the value to be empty and
28693       // we have to add an extra watch since ngModel doesn't work well with arrays - it
28694       // doesn't trigger rendering if only an item in the array changes.
28695       if (attr.multiple) {
28696
28697         // Read value now needs to check each option to see if it is selected
28698         selectCtrl.readValue = function readMultipleValue() {
28699           var array = [];
28700           forEach(element.find('option'), function(option) {
28701             if (option.selected) {
28702               array.push(option.value);
28703             }
28704           });
28705           return array;
28706         };
28707
28708         // Write value now needs to set the selected property of each matching option
28709         selectCtrl.writeValue = function writeMultipleValue(value) {
28710           var items = new HashMap(value);
28711           forEach(element.find('option'), function(option) {
28712             option.selected = isDefined(items.get(option.value));
28713           });
28714         };
28715
28716         // we have to do it on each watch since ngModel watches reference, but
28717         // we need to work of an array, so we need to see if anything was inserted/removed
28718         var lastView, lastViewRef = NaN;
28719         scope.$watch(function selectMultipleWatch() {
28720           if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
28721             lastView = shallowCopy(ngModelCtrl.$viewValue);
28722             ngModelCtrl.$render();
28723           }
28724           lastViewRef = ngModelCtrl.$viewValue;
28725         });
28726
28727         // If we are a multiple select then value is now a collection
28728         // so the meaning of $isEmpty changes
28729         ngModelCtrl.$isEmpty = function(value) {
28730           return !value || value.length === 0;
28731         };
28732
28733       }
28734     }
28735 };
28736
28737
28738 // The option directive is purely designed to communicate the existence (or lack of)
28739 // of dynamically created (and destroyed) option elements to their containing select
28740 // directive via its controller.
28741 var optionDirective = ['$interpolate', function($interpolate) {
28742   return {
28743     restrict: 'E',
28744     priority: 100,
28745     compile: function(element, attr) {
28746
28747       if (isDefined(attr.value)) {
28748         // If the value attribute is defined, check if it contains an interpolation
28749         var interpolateValueFn = $interpolate(attr.value, true);
28750       } else {
28751         // If the value attribute is not defined then we fall back to the
28752         // text content of the option element, which may be interpolated
28753         var interpolateTextFn = $interpolate(element.text(), true);
28754         if (!interpolateTextFn) {
28755           attr.$set('value', element.text());
28756         }
28757       }
28758
28759       return function(scope, element, attr) {
28760
28761         // This is an optimization over using ^^ since we don't want to have to search
28762         // all the way to the root of the DOM for every single option element
28763         var selectCtrlName = '$selectController',
28764             parent = element.parent(),
28765             selectCtrl = parent.data(selectCtrlName) ||
28766               parent.parent().data(selectCtrlName); // in case we are in optgroup
28767
28768         if (selectCtrl) {
28769           selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
28770         }
28771       };
28772     }
28773   };
28774 }];
28775
28776 var styleDirective = valueFn({
28777   restrict: 'E',
28778   terminal: false
28779 });
28780
28781 var requiredDirective = function() {
28782   return {
28783     restrict: 'A',
28784     require: '?ngModel',
28785     link: function(scope, elm, attr, ctrl) {
28786       if (!ctrl) return;
28787       attr.required = true; // force truthy in case we are on non input element
28788
28789       ctrl.$validators.required = function(modelValue, viewValue) {
28790         return !attr.required || !ctrl.$isEmpty(viewValue);
28791       };
28792
28793       attr.$observe('required', function() {
28794         ctrl.$validate();
28795       });
28796     }
28797   };
28798 };
28799
28800
28801 var patternDirective = function() {
28802   return {
28803     restrict: 'A',
28804     require: '?ngModel',
28805     link: function(scope, elm, attr, ctrl) {
28806       if (!ctrl) return;
28807
28808       var regexp, patternExp = attr.ngPattern || attr.pattern;
28809       attr.$observe('pattern', function(regex) {
28810         if (isString(regex) && regex.length > 0) {
28811           regex = new RegExp('^' + regex + '$');
28812         }
28813
28814         if (regex && !regex.test) {
28815           throw minErr('ngPattern')('noregexp',
28816             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
28817             regex, startingTag(elm));
28818         }
28819
28820         regexp = regex || undefined;
28821         ctrl.$validate();
28822       });
28823
28824       ctrl.$validators.pattern = function(modelValue, viewValue) {
28825         // HTML5 pattern constraint validates the input value, so we validate the viewValue
28826         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
28827       };
28828     }
28829   };
28830 };
28831
28832
28833 var maxlengthDirective = function() {
28834   return {
28835     restrict: 'A',
28836     require: '?ngModel',
28837     link: function(scope, elm, attr, ctrl) {
28838       if (!ctrl) return;
28839
28840       var maxlength = -1;
28841       attr.$observe('maxlength', function(value) {
28842         var intVal = toInt(value);
28843         maxlength = isNaN(intVal) ? -1 : intVal;
28844         ctrl.$validate();
28845       });
28846       ctrl.$validators.maxlength = function(modelValue, viewValue) {
28847         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
28848       };
28849     }
28850   };
28851 };
28852
28853 var minlengthDirective = function() {
28854   return {
28855     restrict: 'A',
28856     require: '?ngModel',
28857     link: function(scope, elm, attr, ctrl) {
28858       if (!ctrl) return;
28859
28860       var minlength = 0;
28861       attr.$observe('minlength', function(value) {
28862         minlength = toInt(value) || 0;
28863         ctrl.$validate();
28864       });
28865       ctrl.$validators.minlength = function(modelValue, viewValue) {
28866         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
28867       };
28868     }
28869   };
28870 };
28871
28872 if (window.angular.bootstrap) {
28873   //AngularJS is already loaded, so we can return here...
28874   console.log('WARNING: Tried to load angular more than once.');
28875   return;
28876 }
28877
28878 //try to bind to jquery now so that one can write jqLite(document).ready()
28879 //but we will rebind on bootstrap again.
28880 bindJQuery();
28881
28882 publishExternalAPI(angular);
28883
28884 angular.module("ngLocale", [], ["$provide", function($provide) {
28885 var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
28886 function getDecimals(n) {
28887   n = n + '';
28888   var i = n.indexOf('.');
28889   return (i == -1) ? 0 : n.length - i - 1;
28890 }
28891
28892 function getVF(n, opt_precision) {
28893   var v = opt_precision;
28894
28895   if (undefined === v) {
28896     v = Math.min(getDecimals(n), 3);
28897   }
28898
28899   var base = Math.pow(10, v);
28900   var f = ((n * base) | 0) % base;
28901   return {v: v, f: f};
28902 }
28903
28904 $provide.value("$locale", {
28905   "DATETIME_FORMATS": {
28906     "AMPMS": [
28907       "AM",
28908       "PM"
28909     ],
28910     "DAY": [
28911       "Sunday",
28912       "Monday",
28913       "Tuesday",
28914       "Wednesday",
28915       "Thursday",
28916       "Friday",
28917       "Saturday"
28918     ],
28919     "ERANAMES": [
28920       "Before Christ",
28921       "Anno Domini"
28922     ],
28923     "ERAS": [
28924       "BC",
28925       "AD"
28926     ],
28927     "FIRSTDAYOFWEEK": 6,
28928     "MONTH": [
28929       "January",
28930       "February",
28931       "March",
28932       "April",
28933       "May",
28934       "June",
28935       "July",
28936       "August",
28937       "September",
28938       "October",
28939       "November",
28940       "December"
28941     ],
28942     "SHORTDAY": [
28943       "Sun",
28944       "Mon",
28945       "Tue",
28946       "Wed",
28947       "Thu",
28948       "Fri",
28949       "Sat"
28950     ],
28951     "SHORTMONTH": [
28952       "Jan",
28953       "Feb",
28954       "Mar",
28955       "Apr",
28956       "May",
28957       "Jun",
28958       "Jul",
28959       "Aug",
28960       "Sep",
28961       "Oct",
28962       "Nov",
28963       "Dec"
28964     ],
28965     "WEEKENDRANGE": [
28966       5,
28967       6
28968     ],
28969     "fullDate": "EEEE, MMMM d, y",
28970     "longDate": "MMMM d, y",
28971     "medium": "MMM d, y h:mm:ss a",
28972     "mediumDate": "MMM d, y",
28973     "mediumTime": "h:mm:ss a",
28974     "short": "M/d/yy h:mm a",
28975     "shortDate": "M/d/yy",
28976     "shortTime": "h:mm a"
28977   },
28978   "NUMBER_FORMATS": {
28979     "CURRENCY_SYM": "$",
28980     "DECIMAL_SEP": ".",
28981     "GROUP_SEP": ",",
28982     "PATTERNS": [
28983       {
28984         "gSize": 3,
28985         "lgSize": 3,
28986         "maxFrac": 3,
28987         "minFrac": 0,
28988         "minInt": 1,
28989         "negPre": "-",
28990         "negSuf": "",
28991         "posPre": "",
28992         "posSuf": ""
28993       },
28994       {
28995         "gSize": 3,
28996         "lgSize": 3,
28997         "maxFrac": 2,
28998         "minFrac": 2,
28999         "minInt": 1,
29000         "negPre": "-\u00a4",
29001         "negSuf": "",
29002         "posPre": "\u00a4",
29003         "posSuf": ""
29004       }
29005     ]
29006   },
29007   "id": "en-us",
29008   "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;}
29009 });
29010 }]);
29011
29012   jqLite(document).ready(function() {
29013     angularInit(document, bootstrap);
29014   });
29015
29016 })(window, document);
29017
29018 !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>');